UnityEffects(2)之ProjectorShadow(手游上的实时阴影方案)

UnityEffects(2)之(2)ProjectorShadow(手游上的实时阴影方案)

上一篇说到了在unity5.x中实现shadowMap的方法(UnityEffects(1)shadowMap(阴影映射))。但是由于它需要使用DepthTexture有一定的硬件要求(参考这里:http://docs.unity3d.com/Manual/SL-DepthTextures.html),而且是一个posteffect(后期效果),在手机上面还是效率不高。


手游上面的人物阴影一般都是比较取巧的方法(毕竟没有这么多人用机皇:),基本上遵循“够用就好,看起来不错就好”的原则),一种是给人物脚底贴一个黑圈圈,第二种是使用projector。第一种就不提了,效果不好。这里我们就讨论一下后者,使用投影来实现手游中的实时阴影。据说猪场的《功夫熊猫3》中的阴影也是使用类似的方法实现的,效果不错,但是阴影投影到台阶这种不接受阴影的物体就会有一点小穿帮,也是这种方式的一个缺点,如下图:

UnityEffects(2)之ProjectorShadow(手游上的实时阴影方案)_第1张图片

建筑物等静态物体产生的阴影一般用光照烘焙来实现,这里就不讨论了。

江湖惯例先贴图:

 UnityEffects(2)之ProjectorShadow(手游上的实时阴影方案)_第2张图片

工程放在:https://github.com/aceyan/UnityEffects 使用unity5.4

场景是Scene/(2)ProjectorShadow

实现的原理和shadowMap差不多,只不过不生成深度图,而是使用replaceShader生成一张“轮廓”图,使用untiy自带的Projector组件投影到场景中,在shader中计算从而生成阴影效果。使用replaceShader是为了避免渲染“轮廓”图的时候还是用原来复杂的shader,照成不必要的性能浪费。替换后我们只输出纯色(方便测试)或者alpha值到“轮廓”图。

我们生成的“轮廓”图:

UnityEffects(2)之ProjectorShadow(手游上的实时阴影方案)_第3张图片

投影的时候只需要判断该像素的alpha值,alpha为0的不在阴影中,alpha值越小阴影越透明。

 

由于原理和上一篇差不多就不做过多解释了,这里列两点比较值得注意的:

1、渲染“轮廓”图的相机视锥(光锥)的生成方式我们使用了通过场景的包围盒来校正的方法,这种方式比较适合手游,毕竟多数手游需要动态阴影的就是那些人物(其他的都是静态阴影通过光照烘培来实现),这样最大化的利用的这张“轮廓”图,提高了阴影的质量。对应方法是ShadowUtils. SetLightCamera(Bounds b, Camera lightCamera)

参考资料:http://blog.csdn.net/ronintao/article/details/51649664

 

2、当“轮廓”图中的物体贴近边缘的时候阴影会产生bug,如下图,看到阴影被拉长了一条。

UnityEffects(2)之ProjectorShadow(手游上的实时阴影方案)_第4张图片

这是由于“轮廓”图的wrapMode采用使用了clamp导致的,clamp模式就是uv在超过1的时候把图像边缘的像素拉伸,如下图:

UnityEffects(2)之ProjectorShadow(手游上的实时阴影方案)_第5张图片

如何解决呢?两个方法。

1)求包围盒的时候设置一个offset,使包围盒向外扩大一点,这样物体就不会贴着“轮廓”图的边缘了

2)在投影器的shader中使用一张图来做遮罩(下图),这样边缘的像素可以过滤掉,还可以做出边缘的阴影渐隐的效果。

UnityEffects(2)之ProjectorShadow(手游上的实时阴影方案)_第6张图片

上面两种方法都可以从代码中找到。

 

下面我们来对比一下shadowMap,分析一下各自的优缺点:

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相关代码:

UnityEffects(2)之ProjectorShadow(手游上的实时阴影方案)_第7张图片


3.产生和接受阴影的物体都要渲染到深度图

4.比较深度的误差偏移有可能根据平台而不太一样

5.要为接受阴影的物体提供shader

6.不支持半透明物体的阴影

ProjectorShadow

优点

1.不依赖DepthTexture

2.不用为接受阴影的物体提供shader

3.只需要渲染产生阴影的物体

4.性能比shadowMap有优势

5.支持半透明物体阴影,如下图:

UnityEffects(2)之ProjectorShadow(手游上的实时阴影方案)_第8张图片

缺点

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

 

 

 

你可能感兴趣的:(游戏开发,shader,unity3D,图形编程,UnityEffects系列)