UnityEffects(2)之(2)ProjectorShadow(手游上的实时阴影方案)
上一篇说到了在unity5.x中实现shadowMap的方法(UnityEffects(1)之shadowMap(阴影映射))。但是由于它需要使用DepthTexture有一定的硬件要求(参考这里:http://docs.unity3d.com/Manual/SL-DepthTextures.html),而且是一个posteffect(后期效果),在手机上面还是效率不高。
手游上面的人物阴影一般都是比较取巧的方法(毕竟没有这么多人用机皇:),基本上遵循“够用就好,看起来不错就好”的原则),一种是给人物脚底贴一个黑圈圈,第二种是使用projector。第一种就不提了,效果不好。这里我们就讨论一下后者,使用投影来实现手游中的实时阴影。据说猪场的《功夫熊猫3》中的阴影也是使用类似的方法实现的,效果不错,但是阴影投影到台阶这种不接受阴影的物体就会有一点小穿帮,也是这种方式的一个缺点,如下图:
建筑物等静态物体产生的阴影一般用光照烘焙来实现,这里就不讨论了。
江湖惯例先贴图:
工程放在:https://github.com/aceyan/UnityEffects 使用unity5.4
场景是Scene/(2)ProjectorShadow
实现的原理和shadowMap差不多,只不过不生成深度图,而是使用replaceShader生成一张“轮廓”图,使用untiy自带的Projector组件投影到场景中,在shader中计算从而生成阴影效果。使用replaceShader是为了避免渲染“轮廓”图的时候还是用原来复杂的shader,照成不必要的性能浪费。替换后我们只输出纯色(方便测试)或者alpha值到“轮廓”图。
我们生成的“轮廓”图:
投影的时候只需要判断该像素的alpha值,alpha为0的不在阴影中,alpha值越小阴影越透明。
由于原理和上一篇差不多就不做过多解释了,这里列两点比较值得注意的:
1、渲染“轮廓”图的相机视锥(光锥)的生成方式我们使用了通过场景的包围盒来校正的方法,这种方式比较适合手游,毕竟多数手游需要动态阴影的就是那些人物(其他的都是静态阴影通过光照烘培来实现),这样最大化的利用的这张“轮廓”图,提高了阴影的质量。对应方法是ShadowUtils. SetLightCamera(Bounds b, Camera lightCamera)
参考资料:http://blog.csdn.net/ronintao/article/details/51649664
2、当“轮廓”图中的物体贴近边缘的时候阴影会产生bug,如下图,看到阴影被拉长了一条。
这是由于“轮廓”图的wrapMode采用使用了clamp导致的,clamp模式就是uv在超过1的时候把图像边缘的像素拉伸,如下图:
如何解决呢?两个方法。
1)求包围盒的时候设置一个offset,使包围盒向外扩大一点,这样物体就不会贴着“轮廓”图的边缘了
2)在投影器的shader中使用一张图来做遮罩(下图),这样边缘的像素可以过滤掉,还可以做出边缘的阴影渐隐的效果。
上面两种方法都可以从代码中找到。
下面我们来对比一下shadowMap,分析一下各自的优缺点:
优点
通用,物体穿透不会穿帮,能很好的处理遮挡关系。
缺点
1.依赖DepthTexture,浮点深度图,有一点硬件需求。
有硬件要求:http://docs.unity3d.com/Manual/SL-DepthTextures.html
2.unity中深度图不能单独输出,要手动写shader从自带的depthMap中取出深度来保存,比较麻烦。使用替换渲染时,不产生阴影的物体必须替换为白色,不替换会默认黑色,然后黑色又是深度最小值,会使得物体都处于阴影之中,不好控制。
ps:其实1和2都可以通过自定义shader直接将深度渲染到纹理来避免使用自带的_CameraDepthTexture,这样可以忽略硬件的限制。在上一篇有提到:UnityEffects(1)之shadowMap(阴影映射)
unity为移动平台生成shadowMap似乎也是用的类似的方法。如下图,感兴趣的读者可以阅读UnityCG.cginc相关代码:
3.产生和接受阴影的物体都要渲染到深度图
4.比较深度的误差偏移有可能根据平台而不太一样
5.要为接受阴影的物体提供shader
6.不支持半透明物体的阴影
优点
1.不依赖DepthTexture
2.不用为接受阴影的物体提供shader
3.只需要渲染产生阴影的物体
4.性能比shadowMap有优势
5.支持半透明物体阴影,如下图:
缺点
1.是一个trick,不通用
2.不能处理物体对阴影的遮挡,接受阴影的物体和产生阴影的物体有穿透时会穿帮
总体来说ProjectorShadow比较适合移动平台,能模拟出效果不错的实时阴影
扩展:还可以使用pcf优化阴影边界
http://ogldev.atspace.co.uk/www/tutorial42/tutorial42.html
http://blog.csdn.net/candycat1992/article/details/8981370
http://www.cnblogs.com/lancidie/archive/2012/01/18/2325218.html
参考:
http://blog.csdn.net/mobilebbki399/article/details/50240515
http://blog.csdn.net/qq18052887/article/details/50357973
http://www.ceeger.com/forum/read.php?tid=23305