【C++游戏引擎开发】第23篇:基础阴影映射(Shadow Mapping)
一、 传统渲染的阴影困境
1.1 光照计算的局限性
在标准光照模型中(如Phong模型),着色计算仅考虑直接光照对表面的影响,无法自动生成物体间的遮挡阴影。这种缺失导致渲染结果缺乏空间层次感,场景真实性大打折扣。
1.2 阴影的本质定义
阴影是光线被遮挡物阻挡后在接收面上形成的亮度衰减区域。其数学本质可表述为:给定点 P P P在接收面上,当存在遮挡物使光源到 P P P的直线段被阻断时,则 P P P处于阴影中。
∃ Q ∈ Scene , Q ∈ L P ‾ ⇒ P ∈ Shadow \exists Q \in \text{Scene}, Q \in \overline{LP} \Rightarrow P \in \text{Shadow} ∃Q∈Scene,Q∈LP⇒P∈Shadow
其中 L L L为光源位置, L P ‾ \overline{LP} LP表示光源到目标点的线段。
二、阴影映射核心原理
2.1 深度比较范式
阴影映射的核心思想基于相对深度测试:从光源视角记录场景深度信息,在相机渲染时通过比较当前片段与光源视角深度值的相对关系,判断该位置是否被遮挡。
2.2 两阶段渲染流程
- 深度贴图生成阶段:将摄像机置于光源位置,渲染场景深度到纹理(Shadow Map)
- 阴影检测阶段:正常渲染时,将片段坐标转换到光源空间,通过深度比较确定阴影状态
2.3 数学空间变换
关键坐标系变换链包含:
- 模型矩阵(Model Matrix):物体局部空间→世界空间
- 光源视图矩阵(Light View Matrix):世界空间→光源观察空间
- 光源投影矩阵(Light Projection Matrix):观察空间→裁剪空间
最终得到光源空间坐标:
P light = M proj ⋅ M view ⋅ M model ⋅ P local P_{\text{light}} = M_{\text{proj}} \cdot M_{\text{view}} \cdot M_{\text{model}} \cdot P_{\text{local}} Plight=Mproj⋅Mview⋅Mmodel⋅Plocal
三、 深度贴图技术细节
3.1 正交投影 vs 透视投影
- 正交投影:适用于平行光(如方向光),保持物体比例不变
- 透视投影:适用于点光源,产生透视变形效果
正交投影矩阵构造参数:
M ortho = [ 2 r − l 0 0 − r + l r − l 0 2 t − b 0 − t + b t − b 0 0 − 2 f − n − f + n f − n 0 0 0 1 ] M_{\text{ortho}} = \begin{bmatrix} \frac{2}{r-l} & 0 & 0 & -\frac{r+l}{r-l} \\ 0 & \frac{2}{t-b} & 0 & -\frac{t+b}{t-b} \\ 0 & 0 & -\frac{2}{f-n} & -\frac{f+n}{f-n} \\ 0 & 0 & 0 & 1 \end{bmatrix} Mortho= r−l20000t−b20000−f−n2