在看这一篇文章之前你需要有前置知识:我的另一篇文章“【CG】辐射度量学 & PBR”。
这篇文章很大程度上参考了知乎上 Ubp.a大佬 的文章1
基于图像的光照 Image-based Lighting#
在基于物理的渲染中,想要获得非常好的渲染效果往往需要使用光线追踪,或者全局光照技术,
但是这些技术在实时渲染中往往非常复杂且实现起来非常困难。但如果只考虑光源的直接光照,渲染出来的效果又往往非常平淡。而 基于图像的光照(IBL) 则提供了一种简单的方式而提升了非常好的渲染效果。
IBL 通过将一张 cube map 或者 sphere map 贴图作为光源,它的每个像素都可以代表一个入射光。而对于一个着色点来说,
在这个着色点的法线方向的半球上,我们需要对cube map或者sphere map进行采样,我们让采样结果作为入射光 Li(p,ωi)=cubeMapSampling(p,ωi),然后计算反射方程(如果没有自发光项)。
Lo(p,ωo)=∫Hfr(p,ωi,ωo)Li(p,ωi)n⋅ωidωiLo(p,ωo)=∫H(kdfd+fs)Li(p,ωi)n⋅ωidωi根据积分的线性性我们将积分拆成一个漫反射项和镜面反射项。
Lo(p,ωo)=∫HkdfdLi(p,ωi)n⋅ωidωi+∫HfsLi(p,ωi)n⋅ωidωi简化为
Lo(p,ωo)=Ld(ωo)+Ls(ωo)而一旦在实时渲染中涉及到采样,直接来说这个方法是不可行的,所以在实时渲染中,我们需要对这个积分做一些近似,或者进行一些预计算,
把复杂的积分都先计算好,我们会分别预计算漫反射积分和镜面反射积分。
Irradiance Map#
慢反射项为
Ld(ωo)=∫HkdfdLi(ωi)n⋅ωidωi将与积分无关的项提出来
Ld(ωo)=πρ∫HkdLi(ωi)n⋅ωidωi其中
kd=(1−F)⋅(1−metallic)其中 F 是菲涅尔项,而 F 项包含了半程向量,而半程向量与入射角有关,所以不能提出到积分外部,所以我们需要对 kd 做一些简化
kd≈F0+(max{1−roughness,F0}−F0)(1−(n⋅ωo))5此时 kd 项与积分变量无关了
Ld(ωo)≈kdπρ∫HLi(ωi)n⋅ωidωi展开
Ld(ωo)≈kdπρ∫02π∫02πLi(ωi)cosθsinθdθdϕ现在的积分值只取决于法向 n,在法线方向上的半球上决定了入射光的值。

所以我们可以使用一个 cube map 以提供光照来预计算这个积分,最后得到另一个cube map,这个新的cube map我们称作irradiance map。
要求解这个积分我们可以使用蒙特卡洛积分
均匀采样#
我们可以在半球上的角度进行角度空间的均匀采样,并假设 ϕ 和 θ 是独立的那么
它们在蒙特卡洛积分中的联合概率密度为
p(θ,ϕ)=p(θ)⋅p(ϕ)=π/21⋅2π1=0.5π⋅2π1所以
Ld(ωo)≈kdπρN1N21i∑N1j∑N2p(θi,ϕj)Li(θi,ϕj)cosθisinθi代入化简有
Ld(ωo)≈kdρπN1N21i∑N1j∑N2Li(θi,ϕj)cosθisinθi余弦权重采样#
使用余弦权重采样的 PDF 是 p(ω)=πcosθ
就有
Ld(ωo)≈kdπρN1i∑NπcosθLi(ωi)cosθ=kdρN1i∑NL(ωi)
Speular#
在镜面反射部分中,镜面反射不仅取决于法线 n,还取决于观察方向 v 以及材质的粗糙度 α。这意味着如果你想预计算,你需要一个五维的表格(法线3D + 观察方向2D + 粗糙度1D),这在实时渲染中是不可接受的。
我们参考了 games2022 中的描述 对于镜面反射的 BRDF 它非常满足使用下面这个近似公式的使用条件
∫Ωf(x)g(x)dx≈∫ΩGdx∫ΩGf(x)dx⋅∫Ωg(x)dx所以我们对积分做出一个拆分
Lo(p,ωo)≈∫Ωfrdωi∫ΩfrLi(p,ωi)dωi⋅∫Ω+fs(p,ωi,ωo)n⋅ωidωi使用蒙特卡洛积分
Lo(p,ωo)≈(∑k=1N(n⋅ωk)∑k=1NLi(p,ωk)(n⋅ωk))(N1k=1∑Np(ωk,ωo)f(p,ωk,ωo)(n⋅ωk))预滤波环境光 (Pre-filtered Environment Radiance)#
注意到约等号右边的第一项是对 BRDF 中的 NDF 区域中所有的入射光的积分再归一化,这个操作就相当于对IBL 这张图进行 filtering, 在图上的任何一个点上,取这个点周围的一个范围进行平均操作。这个范围由roughness 决定,我们可以通过固定的 roughness 来预计算多张 cube map 并且使用 mipmap 进行保存,根据物体不同的 roughness 在不同的 mipmap 中进行插值获取 L 值
我们就是通过约等号右边的第一项进行预计算
Part 1=∑k=1N(n⋅ωk)∑k=1NLi(p,ωk)(n⋅ωk)BRDF LUT#
我们处理完了第一项,还有一项我们没有处理。我们知道 fs=4(n⋅ωo)(n⋅ωi)D(h)F(ωo,h)G(l,ωo),并且 GGX 重要性采样的标准 PDF 是 p(h)=4(ωo⋅h)D(h)(n⋅h) 我们将其代入第二项有
I≈N1k=1∑N4(ωo⋅hk)D(hk)(n⋅hk)(n⋅ωo)D(hk)F(ωo,hk)G(ωi(k),ωo)(ωo⋅hk)消掉 D(hk),化简得:
I≈N1k=1∑NF(ωo,hk)(n⋅ωo)(n⋅hk)G(ωi(k),ωo)⋅4(ωo⋅hk)2其中 F(ωo,hk)=F0+(1−F0)(1−ωo⋅hk)5
我们令 Fbase=(1−ωo⋅hk)5,则 F=F0(1−Fbase)+Fbase
代入公式
I≈N1k=1∑N[F0(1−Fbase)+Fbase](n⋅ωo)(n⋅hk)G(ωi(k),ωo)(ωo⋅hk)最后展开
I≈F0⋅Scale(N1k=1∑N(1−Fbase)(n⋅ωo)(n⋅hk)G(ωi(k),ωo)(ωo⋅hk))+Bias(N1k=1∑NFbase(n⋅ωo)(n⋅hk)G(ωi(k),ωo)(ωo⋅hk))终于! 我们得到了最后的公式
I≈F0×Scale+Bias其中 Scale 和 Bias 我们可以通过预计算将其存储在一张只有两个通道(R,G)的纹理中,Scale存放在r通道bias存放在g通道,将 x 轴(U 坐标)映射为 cosθv (n⋅ωo), y 轴(V 坐标)映射为 粗 Roughness,这张纹理我们称为 BRDF LUT
下面是一张 BRDF LUT

最后实现后类似这种效果
