本节内容
- 介绍Shadow Mapping基本知识
- Shadow Mapping 背后的一些数学原理
- PCSS实现软阴影
正文
一. Shadow Mapping
问题1:如何做出一个点光源生成的硬阴影效果?
需要渲染场景两趟:
-
第一趟,从点光源出发看向场景,输出一张光源能看到的最浅的深度图,也就是Shadow map。
-
第二趟,从相机的位置出发,渲染场景。
之后借助第一趟的生成Shadowmap,判断场景中的一个点能否被阴影照射到
具体是,在第二趟中,将视线看到的空间中的点,连向Light(连线穿过Shadowmap上的一个像素)。将Shadowmap中存储的深度与连线的深度做比较,若大于ShadowMap中记录的值,则该点在阴影中。(实际操作中,可将摄像机空间中的坐标,通过MVP变换,转换成光源处摄像机空间的坐标,而后使用该坐标的z值与ShadowMap中的深度值进行比较)
有无阴影的效果比较
存在的问题
1. 会发生自遮挡现象
不在阴影中的点连向ShadowMap时,长度可能会大于ShadowMap中记录的值,从而发生自遮挡现象,在不该生成阴影的地方生成阴影。
原因是,ShadowMap中记录的深度是不连续的,被离散到了一个一个像素当中。这些像素区域投射到场景中,会与光源垂直。
在上面这幅图里,当Light在正上方(光线差不多与地面垂直)的是时候,自遮挡的现象较不明显。
当light比较偏的时候(光线与地面法线方向夹角较大),自遮挡现象较明显。
那么如何解决这个问题?
比较直观的方法,做比较的时候加一个范围,相差的值在误差允许的范围内,可判定为不在阴影中。
进一步,可以考虑光源与表面法线夹角大的时候,误差范围设置得大一些,反之则可设得小一些。
但这种方法可能也会引入新的问题
在一些本应该有阴影的位置,因为与遮挡物的距离较近,也会被判定为不在阴影中。
所以一般就会通过调整合适的误差范围,来尽可能地来避免自遮挡现象,然后也不会让影子与遮挡物间的距离离得太远。
一些其他方法(实际使用比较少)
Second-depth shadow mapping
生成shadowmap时既保留最小也次小深度,比较的时候与最小与次小中间的值进行比较。
- 要求物体都需要有正反面。
- 会增加复杂度。
2.会有锯齿的现象发生
原因也是ShadowMap不是连续的,当分别率不够时会产生锯齿。
二. Shadow Mapping 背后的一些数学原理
对于数学中的不等式,实时渲染中常会拿来用作为约等式使用
约等号满足的情况
- 当积分域足够小
- g(x)足够光滑(只在积分域中值域变化较小)
应用在渲染方程中,可以将Visibility的部分与Shading的部分分开计算。
满足下面两个条件之一,可认为近似是准确的。
- 使用的是点光源或者方向光源(积分限很小的时候)
- L与f是平滑的(L是面光源,BRDF是diffuse的时候是平滑的)
三. Percentage closer soft shadows生成软阴影(PCSS)
前面介绍了使用shadowMap来生成硬阴影。
现实中更多的是软阴影(边界过渡较平缓)
(因为现实中更多的是面光源,光源仅是部分被遮挡)
首先了解PCF的概念
Percentage Closer Filtering(PCF)
一种实现反走样的方法。
方法:
在第二趟空间中的点与ShadowMap上像素中的深度值作比较的时候,也与对应像素周围一圈的像素做比较。
最后取平均值。
如何Filter的大小的选择?
小的话,阴影边界锐利
大的话,阴影边界会偏软
不同位置的Filter大小可以不同。(笔尖阴影较硬,远一些笔杆的部分阴影较软。与遮挡物与阴影的距离有关)
要实现这种效果,不同位置的Filter大小需要不一样。
Filter大小的确定方法
上图的情况里,Filter的大小与面光源到遮挡物的垂直距离,Light的面积,形成阴影的面到遮挡物的垂直距离,这三个量有关。(通过三角形相似进行计算)
PCSS的算法
Step1:任何一个shading point 连向光源,在shadowmap里,对应像素点为中心的局部范围内判断该点是否在阴影里。若在阴影里,则说明ShadowMap上对应的像素点显示的是阴影前的遮挡物。
(计算遮挡物的平均深度)
Step2:把ShadowMap上所有Blocker对应的像素的深度值取平均,继而得出filter的大小。
(使用第一步求得的平均深度,决定在该像素点周围的要应用的 Filter大小)
Step3: 应用PCF的方法
第一步会遇到一个问题,如何确定局部范围的大小。
方式一:直接选取固定大小的范围(如5*5)
方式二:
把ShadowMap摆在近平面的位置,由Shading Point连向面光源与ShadowMap相交构成的范围来当作第一步中所需的局部范围。