在做2d游戏的时候,往往会遇到2d场景或角色阴影投射时,无法使用正常的光照投影系统,以前我一般会复制一份要投影的物体进行变换后处理颜色并给透明度就当作影子了,但最近有位朋友说到性能和实际工作效率时提出想用shader来实现这一问题,我就试着写了一个这样的shader。
首先需要让shader绘制出第二份同样的物体,一般来讲就是添加一个pass。
Pass {
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert_offset
#pragma fragment frag_color
ENDCG
}
Pass {
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert_normal
#pragma fragment frag_normal
ENDCG
}
效果是这样的,注意,这里是一个gameobject。
然后把透明遮罩加上,并把阴影部分的透明度在0.5以上的部分设置为0.5,最后在调整好位置。
记得把ZWrite off 加上,否则就会出现看起来是透明的底,却能把同样的物体挡住的现象。像这样:
说道ZWrite的问题,其实挺麻烦的,因为关闭了之后就会使得后面的物体反倒出现在前面,最直接的方法就是定义渲染顺序,直接加上
Tags{"Queue" = "Transparent"}
最终版本的代码如下:
Shader "Custom/Shadow" {
Properties {
_MainTex ("Main Tex", 2D) = "white" {}
_AlphaTex("AlphaTex",2D) = "white"{}
_Offset ("Offset", vector) = (0, 0, 0, 0)
}
CGINCLUDE
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _Offset;
sampler2D _AlphaTex;
float4 _MainTex_ST;
struct v2f {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
v2f vert_normal(appdata_base v) {
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
v2f vert_offset(appdata_base v) {
v2f o;
float4 pos = mul(_Object2World, v.vertex);
o.pos = mul(UNITY_MATRIX_VP, pos + _Offset);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
float4 frag_normal(v2f i) : COLOR {
float4 texcol = tex2D (_MainTex, i.uv);
texcol.w = tex2D(_AlphaTex,i.uv)*texcol.w;
return texcol;
}
float4 frag_color(v2f i) : COLOR {
float4 c;
c = tex2D(_MainTex, i.uv);
c.w = tex2D(_AlphaTex,i.uv)*c.w;
if(c.w >= 0.5)
{
c.r =0;
c.g=0;
c.b=0;
c.w = 0.5f;
}
return c;
}
ENDCG
SubShader {
Tags{"Queue" = "Transparent"}
Pass {
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert_offset
#pragma fragment frag_color
ENDCG
}
Pass {
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert_normal
#pragma fragment frag_normal
ENDCG
}
}
FallBack "Diffuse"
}
最终效果图: