研究过shadow mapping技术的人应该都知道shadow map会有一种叫self-shadowing(有的文章也叫 shadow acne)的问题,如下图所示:
因为shadow map的精度有限,当要渲染的fragment在light space中距Light很远的时候,就会有多个附近的fragement会samper shadow map中同一个texel,但是即使这些fragment在camera view space中的深度值z随xy变化是值变化是很大的,但他们在light space 中的z值(shadow map中的值)却没变或变化很小,这是因为shadow map分辨率低,采样率低导致精度低,不能准确的记录这些细微的变化。
较为简单的解决方案叫做shadow bias ,如下图所示:
就是简单的给shadow map中的z值加上一个偏移值,让这个值变小一点,偏离要渲染的平面一点,这样要渲染的平面就会都处于光照下,不会出现一部分在shadow中一部分在light中了。
但是,这个bias如果太小的话,效果不会太好,如果太大的话就会导致一种叫shadow disconnect的现象,也叫peter-panning。
导致bias的原因有两个,数值精度原因和几何原因,数值精度就是说因为shadow map 的分辨率和存储depth的precision精度不够。几何原因是因为shadow map中的一个texel投影到camera view space场景中会是一个有面积的部分,这个部分会覆盖好几个场景中的fragment或sample,导致这些不同的fragment或sample会获取到相同的shadow map深度值。
简单的加一个固定偏移值的方法不是很灵活,因为如果要渲染的平面的角度如果不同的话,得需要用不同的offset来调节这个问题,产生这个问题的严重程度是跟平面和光源的角度有关系的,如果要渲染的平面与光线的角度很大的话,那么这个offset值需要大一些,角度小的话offset可以小一些,所以我们还可以进一步优化一下,根据这个平面和光源之间的角度来产生这个offset.具体就是把平面的norma和light dir求点积,来调一下这个offset.