KlayGE中的延迟渲染系列文章将讲述在KlayGE 3.11的Deferred Rendering例子中使用的延迟渲染方法,由5篇文章组成。
Deferred Lighting的框架
KlayGE 3.11的例子已经从Deferred Shading改成了更节省带宽的Deferred Lighting。这里先对Deferred Lighting作一个简要的介绍,并假设读者已经了解了Deferred Shading。
Deferred Lighting的渲染架构可以分为三个阶段:
- G-Buffer的生成
- for each light
{
Lighting pass
} - Shading pass
与Deferred Shading不同的是,shading(也就是和材质相关)的计算仅仅发生在最后一个阶段。所以,G-Buffer中需要保存的信息得到极大地减小,甚至不再需要MRT。
Lighting pass
Lighting pass在Deferred Lighting框架处于核心地位,在这里我打算先把lighting pass解析清楚。一旦lighting pass表达好了,G-Buffer所需要保存的信息,以及shading pass能得到的信息也都清楚了。
我以前的系列文章游戏中基于物理的渲染推出了渲染模型总公式:
[latex]L_{o}(\mathbf{v})=\pi\rho(\mathbf{l_c}, \mathbf{v})\otimes \mathbf{c}_{light} (\mathbf{n} \cdot \mathbf{l_c})=(\mathbf{c}_{diff} + \frac {\alpha + 2} {8}(\mathbf{n} \cdot \mathbf{h})^{\alpha} F(\mathbf{c}_{spec}, \mathbf{l_c},\mathbf{h})) \otimes \mathbf{c}_{light} (\mathbf{n} \cdot \mathbf{l_c})[/latex]
再有N个光源的情况下,每个像素的光照响应就是
[latex]L_{o}(\mathbf{v})=\pi\rho(\mathbf{l_{c1}}, \mathbf{v})\otimes \mathbf{c}_{light1} (\mathbf{n} \cdot \mathbf{l_{c1}})[/latex]
[latex]+\pi\rho(\mathbf{l_{c2}}, \mathbf{v})\otimes \mathbf{c}_{light2} (\mathbf{n} \cdot \mathbf{l_{c2}})[/latex]
[latex] + \ldots[/latex]
[latex]+\pi\rho(\mathbf{l_cN}, \mathbf{v})\otimes \mathbf{c}_{lightN} (\mathbf{n} \cdot \mathbf{l_{cN}})[/latex]
对于Deferred shading来说,每一个shading pass就是执行一个
[latex]\pi\rho(\mathbf{l_cn}, \mathbf{v})\otimes \mathbf{c}_{lightn} (\mathbf{n} \cdot \mathbf{l_cn})[/latex]
而对于Deferred lighting来说,公式需要重新整理一下:
[latex]L_{o}(\mathbf{v})=(\mathbf{c}_{diff} + \frac {alpha + 2} {8}(\mathbf{n} \cdot \mathbf{h_1})^{\alpha} F(\mathbf{c}_{spec}, \mathbf{l_{c1}},\mathbf{h_1})) \otimes \mathbf{c}_{light1} (\mathbf{n} \cdot \mathbf{l_{c1}})[/latex]
[latex]+(\mathbf{c}_{diff} + \frac {\alpha + 2} {8}(\mathbf{n} \cdot \mathbf{h_2})^{\alpha} F(\mathbf{c}_{spec}, \mathbf{l_{c2}},\mathbf{h_2})) \otimes \mathbf{c}_{light2} (\mathbf{n} \cdot \mathbf{l_{c2}})[/latex]
[latex]+\ldots[/latex]
[latex]+(\mathbf{c}_{diff} + \frac {alpha + 2} {8}(\mathbf{n} \cdot \mathbf{h_N})^{\alpha} F(\mathbf{c}_{spec}, \mathbf{l_{cN}},\mathbf{h_N})) \otimes \mathbf{c}_{lightN} (\mathbf{n} \cdot \mathbf{l_{cN}})[/latex]
[latex]=\mathbf{c}_{diff}\otimes (\mathbf{c}_{light1} (\mathbf{n} \cdot \mathbf{l_{c1}}) + \mathbf{c}_{light2} (\mathbf{n} \cdot \mathbf{l_{c2}}) + \ldots + \mathbf{c}_{lightN} (\mathbf{n} \cdot \mathbf{l_{cN}}))[/latex]
[latex]+ \frac {\alpha + 2} {8}(((\mathbf{n} \cdot \mathbf{h_1})^{\alpha} F(\mathbf{c}_{spec}, \mathbf{l_{c1}},\mathbf{h_1})) \otimes \mathbf{c}_{light1} (\mathbf{n} \cdot \mathbf{l_{c1}})[/latex]
[latex]+ ((\mathbf{n} \cdot \mathbf{h_2})^{\alpha} F(\mathbf{c}_{spec}, \mathbf{l_{c2}},\mathbf{h_2})) \otimes \mathbf{c}_{light2} (\mathbf{n} \cdot \mathbf{l_{c2}})[/latex]
[latex]+ \ldots[/latex]
[latex]+ ((\mathbf{n} \cdot \mathbf{h_N})^{\alpha} F(\mathbf{c}_{spec}, \mathbf{l_{cN}},\mathbf{h_N})) \otimes \mathbf{c}_{lightN} (\mathbf{n} \cdot \mathbf{l_{cN}}))[/latex]
由于cdiff是到最后的shading pass才计算,所以在每一个light pass里面,diffuse和specular必须分开才能保证结果正确:
[latex]Diffuse: \mathbf{c}{lightn} (\mathbf{n} \cdot \mathbf{l_{cn}})[/latex]
[latex]Specular: ((\mathbf{n} \cdot \mathbf{h_n})^{alpha} F(\mathbf{c}_{spec}, \mathbf{l_{cn}},\mathbf{h_n})) \otimes \mathbf{c}_{lightn} (\mathbf{n} \cdot \mathbf{l_{cn}})[/latex]
为了把diffuse和specular放入4个通道的buffer中,就只能牺牲specular的颜色,只剩下亮度,同时cspec也简化成一个标量。所以,lighting pass的计算成了:
[latex]float4(1, 1, 1, (\mathbf{n} \cdot \mathbf{h_n})^{\alpha} F(c_{spec}, \mathbf{l_{cn}},\mathbf{h_n})) \times \mathbf{c}_{lightn} (\mathbf{n} \cdot \mathbf{l_{cn}})[/latex]
本系列的第一篇暂告一段落,下一篇将介绍G-Buffer的分配。
Comments