在OpenGL渲染器中已经实现了硬阴影以及PCF,PCSS,在这里再引入级联阴影
级联阴影
传统阴影做法与问题
截图来自我的OpenGL延迟渲染器
|
|
这行代码决定了从光源位置渲染阴影贴图的正交投影矩阵,他决定了阴影的覆盖范围,当设置为10时,硬阴影以及PCSS效果如下


当设置为100时,硬阴影与PCSS效果如下,可以看到硬阴影锯齿变得严重起来,软阴影也糊成一片了


最后设置为1000,阴影以及完全失效了,因为覆盖区域太大了,整个模型也就占几个像素,导致模型边缘区域都是一样的判断结果,另外bias也失效了

所以使用大场景时,阴影需要覆盖很大的区域,导致一大片位置只在阴影贴图中占一小部分,会导致近处模型阴影明显出问题
级联阴影的原理

- 首先对摄像机坐标系下的视锥体分割,分割为不同深度的分段
- 在光源的视角下,生成每个视锥体分段的“包围盒”,这个包围盒是生成阴影贴图时正交投影的重要参考
视锥体分段
目的是把相机的视锥体(camera frustum)沿深度方向划分成多个“级联”
常用方法叫PSSM

- ds表示阴影贴图的像素长度
- dp屏幕像素长度
- dp/ds可以理解为阴影的锯齿误差
- 为了使整个画面的阴影看起来质量一致,不因到相机的距离而发生明显质量变化, 应该让dp/ds 是一个常数(dp/ds:表示“一个阴影贴图像素在屏幕上看起来有多大”)
- 由dp/dy = n/z,得出dp = ndy/z
- φ和θ分别表示曲面法线与屏幕和阴影贴图平面之间的角度。由dz/cosθ = dy/cosφ,得出dy = dzcosφ/cosθ
- 所以dp = ndzcosφ/zcosθ,dp/ds = ndzcosφ/zdscosθ
看看这个式子:
$$ \frac{dp}{ds} = \frac{n dz \cos\phi}{z \, ds \cos\theta} $$它告诉你阴影质量受哪些因素影响:
| 因素 | 影响 | 含义 |
|---|---|---|
| n / z | ↓ 随距离增大而减小 | 物体越远,阴影在屏幕上越小 → 锯齿更明显 |
| cosφ / cosθ | 与法线角度相关 | 面倾斜时投影面积不同,阴影更“拉伸” |
| dz/ds | 光源深度变化与贴图分辨率关系 | 光源投影范围越大(dz 大),每个像素越模糊 |
| → dp/ds 越大,阴影越锯齿 |
- 最后如果用对数拆分方案,可以推导出

其中Z是视锥体分段处的值,对应上图中的Ci,n是近平面距离,f是远平面距离,N是视锥体分割的个数,一般是1~4个
- 如果使用均匀拆分方案

- 而PSSM方法是他们的折中,用系数λ来加权平均,

|
|
到这里就拿到了每个视锥体切片的Near和Far是多少,就是上图中的C0,C1…
光源空间中正交投影
- 先计算出摄像机视锥体分块在世界空间中的坐标(就是计算了近平面和远平面组成的立方体的8个顶点的世界坐标)
|
|
- 利用分块的各顶点坐标,计算摄像机视锥体分段的“包围盒”,从而计算出分块对应的正交投影矩阵(最终结果就是每个级联块都有了自己的变换矩阵,我想把模型放在哪个级联块中,就乘以他的变换矩阵)
|
|
- 计算出摄像机视锥体分块的远平面在摄像机空间中投影后的位置,并把他变换到[0.0,1.0]。这么做的目的是为了在中判断某个片段属于哪个分块
|
|