【UnityShader】游戏角色服饰染色

现在的大部分游戏都有给角色身上的服饰染色的功能。有的是给出几种染色的配色方案供玩家选择,还有的是直接开发染色区域,在区域里可以自定义染色颜色。

这里用unity实现一下染色功能,主要思路就是用一张mask的四通道划分染色的区域。
染色
这里没有做其他光照计算,仅做了染色的部分,材质面板:
材质面板

使用代码把材质面板接入UI操控,就可以让玩家自定义染色的颜色了。

具体实现方案:

首先求初始颜色的luminance

inline half luminance(half3 c)
{
	return dot(float3(0.2125, 0.7154, 0.0721), c);
}

然后采样mask,mask的rgb通道分别控制三块染色区域,a通道则负责识别染色与非染色区域:

half3 SamplerTex_Dye(sampler2D mainTex, sampler2D dyeTex, float2 uv, half4 dyeColor0, half4 dyeColor1, half4 dyeColor2)
{
	half4 texColor = tex2D(mainTex, uv);
	half4 dye = tex2D(dyeTex, uv);

	half dyeFlag0 = dye.r * dye.a;
	half dyeFlag1 = dye.g * dye.a;
	half dyeFlag2 = dye.b * dye.a;
	half noChangeFlag = 1 - dye.a;

	half3 color0 = ComputeDyeColor(texColor.rgb, dyeColor0);
	half3 color1 = ComputeDyeColor(texColor.rgb, dyeColor1);
	half3 color2 = ComputeDyeColor(texColor.rgb, dyeColor2);

	return saturate(dyeFlag0*color0 + dyeFlag1*color1 + dyeFlag2*color2 + noChangeFlag*texColor.rgb);
}

其中dyeColor为外部控制,rgb控制染色的颜色,a控制染色的强度。

计算染色颜色的函数ComputeDyeColor:

inline half3 ComputeDyeColor(half3 c, half4 dyeColor)
{
	half brightness = lerp(1, luminance(c), dyeColor.a);
	return brightness * lerp(c.rgb, dyeColor.rgb, dyeColor.a);
}

上图中Unitychan染色的mask:
染色mask
可以看到R通道控制袖子,G通道控制马甲,B通道控制袜子。
注意mask图导入Unity的时候,压缩格式需要选择带A通道的,且勾上Alpha is Transparency。

Shader全部代码:

Shader "Custom/Actor/Tex-Dye"
{
    Properties
    {
        _MainTex ("MainTex", 2D) = "white" {}

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

		_DyeTex ("Dye Tex", 2D) = "black" {}
		_DyeColor0 ("Dye Color 0", Color) = (1,1,1,1)
		_DyeColor1 ("Dye Color 1", Color) = (1,1,1,1)
		_DyeColor2 ("Dye Color 2", Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags { "Queue"="Geometry" "RenderType"="Opaque" }

        LOD 200

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
			#include "Lighting.cginc"			

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

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

            sampler2D _MainTex;
            float4 _MainTex_ST;
			half4 _Color;			

			sampler2D _DyeTex;
			half4 _DyeColor0;
			half4 _DyeColor1;
			half4 _DyeColor2;

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

			inline half luminance(half3 c)
			{
				return dot(float3(0.2125, 0.7154, 0.0721), c);
			}

			inline half3 ComputeDyeColor(half3 c, half4 dyeColor)
			{
				half brightness = lerp(1, luminance(c), dyeColor.a);
				return brightness * lerp(c.rgb, dyeColor.rgb, dyeColor.a);
			}

			half3 SamplerTex_Dye(sampler2D mainTex, sampler2D dyeTex, float2 uv, half4 dyeColor0, half4 dyeColor1, half4 dyeColor2)
			{
				half4 texColor = tex2D(mainTex, uv);
				half4 dye = tex2D(dyeTex, uv);

				half dyeFlag0 = dye.r * dye.a;
				half dyeFlag1 = dye.g * dye.a;
				half dyeFlag2 = dye.b * dye.a;
				half noChangeFlag = 1 - dye.a;

				half3 color0 = ComputeDyeColor(texColor.rgb, dyeColor0);
				half3 color1 = ComputeDyeColor(texColor.rgb, dyeColor1);
				half3 color2 = ComputeDyeColor(texColor.rgb, dyeColor2);

				return saturate(dyeFlag0*color0 + dyeFlag1*color1 + dyeFlag2*color2 + noChangeFlag*texColor.rgb);
			}

            fixed4 frag (v2f i) : SV_Target
            {
                return half4(SamplerTex_Dye(_MainTex, _DyeTex, i.uv, _DyeColor0, _DyeColor1, _DyeColor2), 1);
            }
            ENDCG
        }
    }
}
  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值