说到实时阴影,现在市面上各个项目实现的实时阴影大部分都是平面阴影,比如王者荣耀实现的实时阴影以及一些RPG网络游戏实现实时阴影,所以项目在设计地形时都是有意回避地形高度差的出现,尽量让地形是平坦的。本篇博客介绍的实时阴影是可以在平面以及地形上进行的渲染。这样实现的实时阴影就可以在不同的地形上进行投影,实现方式采用的还是比较传统的实时阴影算法比如ShadowMap,CSM算法或者PSM算法等等都可以实现出来,另外,除了阴影投影到地面上的,我们还可以实现阴影的自投影,比如角色身上的盔甲可以投影到身体上面,类似崩坏三实现的效果。如下所示:
角色的投影地面并不是平坦的,再看一下自身投影的实现效果:
角色身上的头发或者裙子在自己身上投影。自身的投影实现相对来说比较耗,它要实时的计算遮挡关系。下面先给读者介绍将投影投到任意地形上面,实现的算法可以使用CSM算法,这个也是Unity引擎使用的算法。CSM算法是通过摄像机根据距离对场景由远及近进行划分,近处的物体投影比较精细,远处的物体投影相对来说比较简陋,这样对性能来说也是一种优化,如下所示:
摄像机生成好了后,需要加入Shader生成阴影其实简单点说就是像素深度的判断
代码如下所示:
fixed4 frag (v2f i) : COLOR{float depth = i.depth.x/i.depth.y;#if defined (SHADER_TARGET_GLSL) depth = depth*0.5 + 0.5; //(-1, 1)-->(0, 1)#elif defined (UNITY_REVERSED_Z)depth = 1 - depth; //(1, 0)-->(0, 1)#endifreturn EncodeFloatRGBA(depth);}
我们投影是投影到地面上或者墙上,从优化角度讲,我们会选择哪些可以接收阴影,哪些不接受阴影。这些需要接收的阴影的对象需要挂接一个Shader用于接收阴影,片段着色器代码如下所示:
fixed4 frag (v2f i) : COLOR0 {fixed4 weights = getCascadeWeights(i.eyeZ);fixed4 coord = getShadowCoord(i.worldPos, weights);i.shadowCoord.xy = i.shadowCoord.xy/i.shadowCoord.w;float2 uv = i.shadowCoord.xy;uv = uv*0.5 + 0.5; //(-1, 1)-->(0, 1)fixed4 texcol = tex2D(_MainTex, uv);float depth = i.shadowCoord.z / i.shadowCoord.w;#if defined (SHADER_TARGET_GLSL)depth = depth*0.5 + 0.5; //(-1, 1)-->(0, 1)#elif defined (UNITY_REVERSED_Z)depth = 1 - depth; //(1, 0)-->(0, 1)#endif// sample depth texturefloat4 col = SampleShadowTexture(i.worldPos, weights) * texcol;return col;}
这样我们就完成了阴影的实现,效果如下所示:
这样我们的角色实现了可以将阴影投影到不同的地形上,下面再看看通过设置裁剪距离实现自身投影效果,如下所示:
大家可以看到红色方框内的阴影是角色衣服和武器投影到上面的,完美解决了该问题。
代码后续奉上。。。。。。。。。。