【笔记】PBR初见

发布时间 2023-04-16 21:19:24作者: Relolihentai

尝试在unity中实现类似 标准材质 的PBR材质

 本篇纯粹作为学习笔记记录,基本都是大佬现成的思路以及直接套的公式

PBR辐射率公式想必大家都有所耳闻

\(L_{0}\left(p,w_{0}\right)=\int_{Ω}^{ }\ \left(k_{d}\cdot\frac{c}{\pi}+\frac{D\cdot G\cdot F}{4\cdot\left(w_{0}\cdot n\right)\left(wi\cdot n\right)}\right)\cdot Li\left(p,w_{i}\right)\cdot\left(w_{i}\cdot n\right)\cdot dw_{i}\)

实际上这个公式大部分都已经是定式了,前人已经把所有的所有都总结好了,我们只需要记住公式然后代入就可以了

需要理解的一点是

我们的最终结果 L0 是光线通过一个无限小的立体角 Wi(由于无限小可以当做方向向量)在某一点 P 向 W0 方向(观察方向)反射的辐射率

辐射率本是表示一个区域面积上光线总量的物理量,而当面积和立体角无限小,就可以认为是一束光线在某一点的光的通量

有时候也被称为辐射度,基本可以理解为过去理解的颜色,对统一单位有积极意义

 

下面是各个公式

\(D=\frac{α^{2}}{\pi\cdot\left(\left(n\cdot h\right)^{2}\left(α^{2}-1\right)+1\right)^{2}}\)

\(G=\frac{n\cdot l}{lerp\left(n\cdot l,1,k\right)}\cdot\frac{n\cdot v}{lerp\left(n\cdot v,1,k\right)}\)

\(F=lerp\left(\left(1-\left(n\cdot v\right)^{5}\right),1,F_{0}\right)\)

\(F_{0}=\left(1-F\right)\cdot\left(1-M\right)\)

其中 M 为金属度

在直接光照下

\(k=\frac{\left(α+1\right)^{2}}{8}\)

在简洁光照下

\(k=\frac{1}{α^{2}+1}\)

 

直接光照部分的实现大同小异

在LearnOpenGL中,D 中将 粗糙度的平方改为了四次方

漫反射部分没有除 PI,而在 高光部分 乘上了 PI,使得整体更亮了一些

 

比较复杂的是间接光照部分

对于积分的算法千奇百怪,我们这里使用 Unity 自己做的 积分 和 mipmap

 1           float mip_Level = _Gloss * (1.7 - 0.7 * _Gloss );
 2                 float mip = mip_Level * UNITY_SPECCUBE_LOD_STEPS;
 3                 float3 reflect_dir = reflect(-viewDir, bumpDir);
 4                 //漫反射部分
 5                 float3 A_diffuse = ShadeSH9(float4(bumpDir, 1)) * albedo / PI;
 6                 //return float4(A_diffuse, 1);
 7                 //高光反射部分
 8                 //unity_SpecCube0、UNITY_SAMPLE_TEXCUBE_LOD均为内置
 9                 float4 colorCubeMap = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, reflect_dir, mip_Level);
10                 float3 env_color = DecodeHDR(colorCubeMap, unity_SpecCube0_HDR);
11                 float2 envBRDF  = tex2D(_brdfLUT, float2(max(dot(bumpDir, viewDir), 0.0), _Gloss)).rg;
12                 float3 A_specular = KunDir * env_color * (Ftmp * envBRDF.x + float3(envBRDF.y, envBRDF.y, envBRDF.y));
13                 //最终漫反射
14                 float3 ambient = (KD * A_diffuse + A_specular) * _Ao;

间接光照的BRDF通过采样一张LUT实现,具体原理非常复杂

将图放到下面

 

PBR直接光照部分的文章非常之多非常之细,而间接光照但凡深入一点就需要手搓积分

其中LearnOpenGL感觉比较明白,代码也好理解

参考资料

猴子都能看懂的PBR - 知乎 (zhihu.com)

理论 - LearnOpenGL CN (learnopengl-cn.github.io)