【Unity Shader】Unity中阴影走样的解决方案

走样问题出现在两个地方:

  • 初始采样:获得shadowmap的过程
  • 重采样:从摄像机视角对Shadowmap进行重采样

这两个阶段都会产生走样问题。

1 初始采样-透视走样

1.1 形成原因

这里的情况其实跟纹理类似,是由于近景大量pixel与shadowmap中的同一个texel对应导致的走样。详细一点的解释如下图:

从光源位置采样获得shadowmap时,此时摄像机并没有进行透视投影,shadowmap在世界空间是均匀分配的。如上左图所示:橙色箭头位置对应的三个texel都对应着世界空间下相同大小的pixel,此时的pixel数量分配还保持着近平面小所以少,远平面大所以多。

由于世界空间变换到屏幕空间需要经过透视投影,透视投影后原本大小不一样的近平面和远平面在屏幕内所占pixel变得一样了,但是前面获取的shadowmap和视锥体内物体的对应关系并没有改变,这导致了什么?——对于近平面/前景,shadowmap的一个texel将对应屏幕里的很多pixel,因此就会出现下述情况:

虽然远处的A和近处的B明明分辨率是一样的,但图中靠近摄像机B的阴影就出现了明显的块状感,也就是透视走样。

1.2 解决方案-CSM

其实有两种解决办法,第一种就是在光源位置采样获得shadowmap之前,我们先做一次透视投影,那就不会出现透视投影之后一个texel对应的pixel远、近平面不一样的情况了。

第二种解决办法,级联阴影映射(Cascaded Shadow Map),它也是目前公认的透视走样最有效的解决思路。

CSM的想法思路

采取某种办法尽量减少近平面和远平面之间的像素差距,像素差距小了,那透视对texel覆盖关系的影响不就少了!

CSM的具体办法

从它的解决办法看,级联阴影映射又可以叫做多重阴影映射,因为说白了就是一种采用多张shadowmap去实现阴影的技术。具体操作:通过平行于视图方向的切片将视锥体截成多个子视锥体,每一个子视锥体都对应一张shadowmap,每张shadowmap独立计算但分辨率相同,如下图:

对于级联的划分,一般采用对数划分,具体划分我直接截图了(图来自7.2 Shadow Map

还需知道的是:如果真的在view space也就是视锥体划分级联,一旦镜头转动会产生很严重的闪烁,所以一般划分级联是在光源空间中划分。(参考DX12渲染管线(6) - 级联阴影与距离场阴影中的说法)

1.3 Unity中的CSM

Unity可以在Project setting里可以进行级联阴影分级的设置:

  • Shadow Cacades

Unity提供2和4两种划分方案,一般来讲4已经足够了。

  • Cascade splits

图里选择的是Four Cascades,底下0-4咋占比越来越大?结合下图来看,每张shadowmap的分辨率是相同的,但是离摄像机越近的子视锥体它的质量应该越高,越远的质量越低,相同分辨率的条件下当然是越精细/小,细节刻画的就越细致。所以0-3是按照近->远分的,这样划分还可以充分利用资源。

  • Shadow Distance

 用来控制近平面到级联阴影的最远距离,整个级联阴影也是只在这个范围内产生阴影,这也减少了阴影带来的开销。

查看shadowmap绘制过程

在Unity里随便搭一个阴影相对较多的场景,在Frame Debug里查看shadowmap的整个绘制过程,会发现它就是按照4张分别进行的,如下图:

2 重采样走样

关于这个其实就是Games202作业1的内容了,我在GAMES202作业1-实现过程详细步骤中也详细说明了PCF和PCSS是如何实现的,展示了过程,这里我不再赘述~ 

Unity中的阴影类型

用户是可以通过选择Light组建的Shadow Type来选择阴影的Hard/Soft。

至于Unity中具体是如何实现的,打算去学校图书馆借来《Unity 3D 内建着色器源码剖析》那本书看看,后期肯定对管线搭建的学习有所帮助,这里就不再说了。


最后我只想说,阴影这里只学到PCF和PCSS是远远不够的。因为Unity已经给我们把关键的东西都写好了,内置着色器往往帮了一个大忙。网上也有很多大佬抛弃Unity自己搭建一个阴影系统, 例如实时渲染-阴影渲染实现(Unity)等等,后期我也会尝试srp管线的搭建,那时一定会重新捡起来阴影这部分继续深入学习。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九九345

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值