基于物理的渲染(2):渲染方程
基于物理的渲染(2):渲染方程
其中\(L_o\)为P点的出射辐射率,\(f_r\)是P点入射方向到出射方向光的反射比,也叫双向反射分布函数(BRDF),\(L_i\)是P点入射光辐射率。渲染方程说明了P点的出射辐射率,可以通过半球 \(Ω\)内所有入射方向光线辐射率乘以\(f_r\),和余弦值 \(n⋅ω_i\) 。
5.1 双向反射分布函数(BRDF)
BRDF表示材质性质,用于描述表面反射和次表面反射,分别用作高光反射项和漫反射项。举例来说,如果一个平面拥有完全光滑的表面(比如镜面),那么对于所有的入射光线ωi(除了一束以外)而言BRDF函数都会返回0.0 ,只有一束与出射光线ωo拥有相同(被反射)角度的光线会得到1.0这个返回值。
Cook-Torrance BRDF模型既有漫反射项又有高光反射项,在实时渲染中最为常用:
其中,\(k_d\) 为入射光线中被折射部分能量的比例,\(k_s\) 为被反射的比例。Lambertian漫反射模型如下
$$f_{lambert}=\frac{c}{\pi}$$
c为表面颜色。Cook-Torrance 高光反射模型如下
其中包含三个函数,D表示法线分布函数(Normal Distribution Function),F表示菲涅尔方程(Fresnel Equation),和G表示几何函数(Geometry Function)。
5.2 法线分布函数
法线分布函数用于估算微平面中法线和半程向量一致的平面数量,Trowbridge-Reitz GGX公式:
其中h表示半程向量,a表示表面粗糙度。如下图所示,粗糙度越大,微平面半程向量越分散,表面更加灰暗。
5.3 菲涅尔方程
菲涅尔方程描述的是被反射的光线对比被折射的光线所占比例。当光线碰撞到一个表面时,菲涅尔方程会根据观察角度计算得到被反射的光线的比例。菲涅尔方程是个相当复杂的方程式,一般用Fresnel-Schlick近似法求得近似解:
$$F_{Schlick}(h,v,F_0)=F_0+(1-F_0)(1-(hv))^5$$
其中 \(F_0\) 表示平面的基础反射率,它通过折射指数计算得到。当视线和表面法线夹角越接近90度,菲涅尔现象越明显,反光越强。Fresnel-Schlick近似法只对电介质有意义,可以通过金属度纹理插值近似得到:
vec3 F0 = vec3(0.04);
F0 = mix(F0, surfaceColor.rgb, metalness);
然后计算得到实际反射率:
vec3 fresnelSchlick(float cosTheta, vec3 F0)
{
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}
5.4 几何函数
几何函数表示了微平面相互遮挡的比例,如下图所示分为两种情况:观察方向上的集合遮蔽和光线方向上的几何阴影。
我们可以用Smith函数将两部分放到一起:
$$G(n,v,l,k)=G_{sub}(n,v,k)⋅G_{sub}(n,l,k)$$
材料的粗糙度越高,微平面相互遮蔽的概率越高,Schlick-GGX几何函数
$$G_{SchlickGGX}(n,v,k)=\frac{n⋅v}{(n⋅v)(1−k)+k}$$
其中k由粗糙度计算而来,直接光照和环境光照参数分别为:
$$k_{direct}=\frac{(α+1)^2}{28}$$
$$k_{IBL}=\frac{α^2}{2}$$
glsl代码如下:
float GeometrySchlickGGX(float NdotV, float k)
{
float nom = NdotV;
float denom = NdotV * (1.0 - k) + k;
return nom / denom;
}
float GeometrySmith(vec3 N, vec3 V, vec3 L, float k)
{
float NdotV = max(dot(N, V), 0.0);
float NdotL = max(dot(N, L), 0.0);
float ggx1 = GeometrySchlickGGX(NdotV, k); // 视线方向的几何遮挡
float ggx2 = GeometrySchlickGGX(NdotL, k); // 光线方向的几何阴影
return ggx1 * ggx2;
}
这样得到最终的渲染方程: