1、让透明度测试Shader投射阴影
(1)同样我们使用FallBack的形式投射阴影,但是需要注意的是,FallBack的内容为:Transparent / Cutout / VertexLit,该默认Shader中会把裁剪后的物体深度信息写入到 阴影映射纹理和摄像机深度图中
注意:使用该默认Shader计算投射阴影时,需要使用_Cutwoff属性 和 _Color属性来进行相关计算,因此我们必须保证我们的Shader当中有名为_Cutoff的阈值属性 和 _Color的漫反射颜色属性,否则无法得到正确阴影结果
(2)为了得到正确的阴影效果,我们需要将该物体的Cast Shadows(投射阴影)属性设置为Two Sided(双面),强制让Unity计算阴影隐射纹理时计算所有面的深度信息。因为如果不设置,默认将物体渲染到阴影隐射纹理和摄像机深度图时只会考虑物体的正面,背对光源的面不会参与计算(左图),设置为双面后即可参与计算,得到正确的结果(右图)。
3、让透明度测试Shader接收阴影
主要分5步骤:
(1)编译指令:#pragma multi_compile_fwdbase
用于帮助我们编译所有变体 并且保证衰减相关光照变量能够正确赋值到对应的内置变量中
(2)包含内置文件: #include "AutoLight.cginc"
(3)结构体中声明阴影坐标宏:SHADOW_COORDS(n)
n为下一个可用的插值寄存器的索引值(结构体前面有几个TEXCOORD就填几)
(4)坐标转换宏:TRANSFER_SHADOW(o);
(5)Unity光照衰减计算宏:UNITY_LIGHT_ATTENUATION(atten, v2f结构体, 顶点世界坐标位置);
Shader "ShaderProj/4/TranparentTest_Both"
{
Properties
{
_MainTex("MainTex", 2D) = ""{}
_Color("MainColor", Color) = (1,1,1,1)
_SpecularColor("SpecularColor", Color) = (1,1,1,1)
_SpecularNum("SpecularNum", Range(0,20)) = 15
_Cutoff("CutOff", Range(0,1)) = 0 // 透明度测试阈值
}
SubShader
{
Tags{
"Queue"="AlphaTest"
"IgnoreProjector"="True"
"RenderType"="TransparentCutout"
}
Pass
{
Tags { "LightMode"="ForwardBase" }
// 关闭剔除,正面背面都被渲染
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
fixed4 _SpecularColor;
float _SpecularNum;
fixed _Cutoff;
struct v2f
{
float4 pos:SV_POSITION;
float2 uv:TEXCOORD0;
float3 wNormal:NORMAL;
float3 wPos:TEXCOORD01;
SHADOW_COORDS(2)
};
fixed3 getLambertColor(float3 normal, float3 lightDir, fixed3 albedo)
{
fixed3 color = _LightColor0 * albedo * max(0, dot(lightDir, normal));
return color;
}
fixed3 getSpecularColor(float3 worldPos, float3 normal, float3 lightDir)
{
//float3 viewDir = normalize(_WorldSpaceCameraPos - worldPos);
float3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
float3 halfAngle = normalize(viewDir + lightDir);
fixed3 color = _LightColor0 * _SpecularColor * pow(max(0, dot(normal, halfAngle)), _SpecularNum);
return color;
}
v2f vert (appdata_base v)
{
v2f data;
data.pos = UnityObjectToClipPos(v.vertex);
data.wNormal = UnityObjectToWorldNormal(v.normal);
data.wPos = mul(unity_ObjectToWorld, v.vertex);
data.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
//data.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
TRANSFER_SHADOW(data)
return data;
}
fixed4 frag (v2f i) : SV_Target
{
// 透明度测试
fixed4 texColor = tex2D(_MainTex, i.uv);
clip(texColor.a - _Cutoff);
//计算光照衰减和阴影衰减的宏
UNITY_LIGHT_ATTENUATION(atten, i, i.wPos)
fixed3 albedo = texColor.rgb * _Color.rgb;
float3 lightDir = normalize(_WorldSpaceLightPos0);
fixed3 lambertColor = getLambertColor(i.wNormal, lightDir, albedo);
fixed3 specularColor = getSpecularColor(i.wPos, i.wNormal, lightDir);
fixed3 color = (lambertColor + specularColor) * atten + UNITY_LIGHTMODEL_AMBIENT.rgb * albedo;
return fixed4(color, 1);
}
ENDCG
}
}
Fallback "Transparent/Cutout/VertexLit"
}
3、透明度混合处理阴影
根据透明度测试的思路,我们如果想要物体产生阴影效果无非就两步:
(1)投射阴影
在FallBack中关联内置的对应Shader("Transparent/VertexLit")
(2)接受阴影
在Shader中书写计算阴影衰减值的相关代码
因此对于透明度混合的Shader也会使用同样的思路去制作
但是!!!由于透明度混合需要关闭深度写入,而阴影相关的处理需要用到深度值参与计算,因此Unity中从性能方面考虑(要计算半透明物体的的阴影表现效果是相对复杂的),所有的内置半透明Shader都不会产生阴影效果(比如 Transparent/ VertexLit)
因此
2 - 1.透明混合Shader想要 投射阴影时
不管你在FallBack中写入哪种自带的半透明混合Shader,都不会有投射阴影的效果,因为深度不会写入
2 - 2.透明混合Shader想要 接受阴影时
Unity内置关于阴影接收计算的相关宏,不会计算处理透明混合Shader【混合因子 设置为半透明效果(Blend SrcAlpha OneMinusSrcAlpha)的Shader】
因为透明混合物体的深度值和遮挡关系无法直接用传统的深度缓冲和阴影贴图来处理
结论:Unity中不会直接为透明度混合Shader处理阴影
4、透明度混合强制生成阴影
在FallBack中设置一个非透明Shader,比如VertexLit、Diffuse等,用其中的灯光模式设置为阴影投射的渲染通道来参与阴影映射纹理的计算,把该物体当成一个实体物体处理,但是,这种效果并不真实,不建议使用