一,Planar Shadow
原理就是将模型压扁之后绘制在需要接受阴影的物体上,这种方式十分高效,消耗很低。具体实现过程参考Unity Shader - Planar Shadow - 平面阴影。具按照自己的理解,其实就是根据光照方向计算片元在接受阴影的平面上的投影位置,然后绘制即可,这种方式还是只适合在平面上绘制阴影。
PlanarShadow.shader
Shader "Custom/PlanarShadow"
{Properties{_Tint("_Tint", Color) = (1,1,1,1)_MainTex("_MainTex (albedo)", 2D) = "white" {}[Header(Alpha)][Toggle(_CLIPPING)] _Clipping ("Alpha Clipping", Float) = 1_Cutoff("_Cutoff (Alpha Cutoff)", Range(0.0, 1.0)) = 0.5 // alpha clip threshold[Header(Shadow)]// _GroundHeight("_GroundHeight", Range(-100, 100)) = 0_GroundHeight("_GroundHeight", Float) = 0_ShadowColor("_ShadowColor", Color) = (0,0,0,1)_ShadowFalloff("_ShadowFalloff", Range(0,1)) = 0.05// Blending state[HideInInspector] _SrcBlend("__src", Float) = 1.0[HideInInspector] _DstBlend("__dst", Float) = 0.0[HideInInspector] _ZWrite("__zw", Float) = 1.0[HideInInspector] _Cull("__cull", Float) = 2.0}SubShader{Pass {// 其他Pass请自行实现}// Planar Shadows平面阴影Pass{Name "PlanarShadow"//用使用模板测试以保证alpha显示正确Stencil{Ref 0Comp equalPass incrWrapFail keepZFail keep}Cull Off//透明混合模式Blend SrcAlpha OneMinusSrcAlpha//关闭深度写入ZWrite off//深度稍微偏移防止阴影与地面穿插Offset -1 , 0CGPROGRAM#pragma shader_feature _CLIPPING#pragma shader_feature _ALPHATEST_ON#pragma shader_feature _ALPHAPREMULTIPLY_ON#include "UnityCG.cginc"#pragma vertex vert#pragma fragment fragfloat _GroundHeight;float4 _ShadowColor;float _ShadowFalloff;half4 _Tint;sampler2D _MainTex;float4 _MainTex_ST;float _Clipping;half _Cutoff;struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float4 vertex : SV_POSITION;float4 color : COLOR;float2 uv : TEXCOORD0;};float3 ShadowProjectPos(float4 vertPos){float3 shadowPos;//得到顶点的世界空间坐标float3 worldPos = mul(unity_ObjectToWorld , vertPos).xyz;//灯光方向// float3 lightDir = normalize(_LightDir.xyz);float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);//阴影的世界空间坐标(低于地面的部分不做改变)shadowPos.y = min(worldPos .y , _GroundHeight);shadowPos.xz = worldPos .xz - lightDir.xz * max(0 , worldPos .y - _GroundHeight) / lightDir.y; return shadowPos;}float GetAlpha (v2f i) {float alpha = _Tint.a * tex2D(_MainTex, i.uv.xy).a;return alpha;}v2f vert (appdata v){v2f o;//得到阴影的世界空间坐标float3 shadowPos = ShadowProjectPos(v.vertex);//转换到裁切空间o.vertex = UnityWorldToClipPos(shadowPos);//得到中心点世界坐标float3 center = float3(unity_ObjectToWorld[0].w , _GroundHeight , unity_ObjectToWorld[2].w);//计算阴影衰减float falloff = 1-saturate(distance(shadowPos , center) * _ShadowFalloff);//阴影颜色o.color = _ShadowColor;o.color.a *= falloff;o.uv = TRANSFORM_TEX(v.uv, _MainTex);return o;}fixed4 frag (v2f i) : SV_Target{if (_Clipping){float alpha = GetAlpha(i);i.color.a *= step(_Cutoff, alpha);}return i.color;}ENDCG}}// FallBack "Diffuse"
}
二,Projector Shadow
Projector Shadow是常用的实时阴影实现方式,其基本原理是通过摄像机将需要显示阴影的物体,渲染到一张RenderTexture(RT)上,记录下物体的颜色值(可设置为自定义颜色),并将RT关联到Projector组件的材质上;然后通过Projector组件将需要接收阴影的物体以Projector组件的材质再渲染一遍来实现阴影的显示。
可下载这个插件DynamicShadowProjector
结构是这样的