欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

移动端实时阴影+自投影技术实现

程序员文章站 2022-07-13 14:57:01
...

说到实时阴影,现在市面上各个项目实现的实时阴影大部分都是平面阴影,比如王者荣耀实现的实时阴影以及一些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)
		#endif

			return 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 texture
				float4 col = SampleShadowTexture(i.worldPos, weights) * texcol;
				return col;
			}	

这样我们就完成了阴影的实现,效果如下所示:
移动端实时阴影+自投影技术实现
这样我们的角色实现了可以将阴影投影到不同的地形上,下面再看看通过设置裁剪距离实现自身投影效果,如下所示:
移动端实时阴影+自投影技术实现
大家可以看到红色方框内的阴影是角色衣服和武器投影到上面的,完美解决了该问题。

代码后续奉上。。。。。。。。。。