最近有个需求:通过一张贴图的颜色值来控制材质主贴图的透明度。
先做一个注明:用来控制主贴图透明度的贴图,我们暂且称之为“Alpha贴图”;主贴图就叫“主贴图”。
首先,我们需要解决的是将Alpha贴图的颜色值转化成透明度;经过多方测试,最终采用了以下方法:1)比较像素点的r、g、b;2)假设r最大,则float val = r*权重+g+b;3)alpha = val/(权重+2)
直接上代码:
Shader "Custom/MainTexAlphaCtrl"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}//主贴图纹理
_AlphaTex("AlphaTexture",2D) = "white"{}//Alpha纹理
_BaseColor("Base Color",Color) = (1, 1, 1, 1)
_Weight("Weight",float) = 0//Alpha计算时的权重
[Toggle(_Reverse)] _Reverse("Reverse", float) = 0//是否取反,用于主贴图的透明度计算
}
SubShader
{
Tags { "RenderType" = "Transparent"}
LOD 100
Cull Off
//如果使用Alpha混合,需要关闭深度缓冲写入
ZWrite Off
//添加混合命令
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
sampler2D _AlphaTex;
float4 _MainTex_ST;
float4 _BaseColor;
float _Weight;
float _Reverse;
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
//将颜色值转化成透明度
float color2Alpha(fixed3 col)
{
float a = 0;
float val = 0;
//比较r、g、b三个值,得到最大值,如果r最大,则val = 4*r+g+b;
if (col.r > col.g)
{
if (col.r > col.b)
{
val = _Weight * col.r + col.g + col.b;
}
else
{
val = _Weight * col.b + col.g + col.r;
}
}
else
{
if (col.g > col.b)
{
val = _Weight * col.g + col.r + col.b;
}
else
{
val = _Weight * col.b + col.g + col.r;
}
}
//然后val除以(权重+2),得到最终alpha值
return val / (_Weight+2);
//return (col.r + col.g + col.b)/3;
}
fixed4 frag(v2f i) : SV_Target
{
// sample the texture
fixed4 main_col = tex2D(_MainTex, i.uv) * _BaseColor;
fixed3 alpha_col = tex2D(_AlphaTex, i.uv).rgb;
if (_Reverse == 0)
{
return fixed4(main_col.rgb, main_col.a * color2Alpha(alpha_col));
}
else
{
return fixed4(main_col.rgb, main_col.a * (1 - color2Alpha(alpha_col)));
}
}
ENDCG
}
}
}