两天前有个朋友想要弄个给图片加阴影的效果找我帮忙,刚开始比较纳闷图片加阴影,怎么个加法,当他发了张图瞬间就懂了,效果是这样的:
原理就是简单的一个UV小幅度的偏移采样得到影子然后和原始UV采样的结果叠加在一起(影子在后面原图在前面)就OK了.(纹理的wrapMode需要设置为Clamp)
完整的Shader:
Shader "Custom/ImageShadow"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_OffsetX ("Offset X", range(-0.2,0.2)) = 0
_OffsetY ("Offset Y", range(-0.2,0.2)) = 0
_ShadowColor ("Shadow Color", COLOR) = (0,0,0,1)
_ThresholdAlpha("Threshold Alpha", Range(0,0.5)) = 0.1
}
SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}
Cull Off
Lighting Off
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
half _OffsetX;
half _OffsetY;
fixed4 _ShadowColor;
half _ThresholdAlpha;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
fixed shadowAlpha = tex2D(_MainTex, i.uv + half2(_OffsetX,_OffsetY)).a;
fixed4 shadowColor = fixed4(_ShadowColor.rgb, _ShadowColor.a * shadowAlpha);
fixed4 finalColor = shadowColor;
fixed stepVal = step(_ThresholdAlpha, col.a);
finalColor = stepVal * col + (1 - stepVal) * shadowColor;
return finalColor;
}
ENDCG
}
}
}
VertShader中就是常规的MVP变换与UV值的计算,主要来看下FragmentShader,
影子的颜色值做为可调参数,采样过程中就只用关心Alpha的值,如下:
fixed shadowAlpha = tex2D(_MainTex, i.uv + half2(_OffsetX,_OffsetY)).a;
fixed4 shadowColor = fixed4(_ShadowColor.rgb, _ShadowColor.a * shadowAlpha);
_OffsetX 与 _OffsetY的作用就是对UV进行偏移计算,然后采样得到影子的alpha的值,在与_ShadowColor影子颜色参数作用在一起得到最终影子的颜色值.
原图的采样结果和阴影的采样结果都准备好了,接下来就叠加在一起就完成了.
fixed stepVal = step(_ThresholdAlpha, col.a);
finalColor = stepVal * col + (1 - stepVal) * shadowColor;
这一步就是找到原图的Alpha值大于阈值_ThresholdAlpha的范围,在这个区域内显示原图颜色值,超过这个区域的则显示阴影颜色值.大功告成.
这里是step方法其实写成if(col.a > _ThresholdAlpha)的可读性更高,因为shader中需要尽量避免条件分支的写法,在老点的GUP上会不支持或影响效率,但是现在的GPU貌似没有这个限制了(这点不是很清楚),不过可以肯定的是用step除了可读性比if稍微低了点而已其他方面都是没有问题的.
这个_ThresholdAlpha的作用就是处理一些图片边缘切的不干净的情况,比如
则可以在不麻烦美术大大的情况下,通过参数调节得到比较满意的效果:
最终效果: