PBR理论(四)

openGL高级光照部分目录 见 openGL高级光照部分目录

法线分布函数

法线分布函数D在统计学上近似于微区的相对表面积,精确地与矢量h对齐。在给定一些粗糙度参数的情况下,有许多NDF在统计上近似于微面总体排列,我们将使用的NDF称为Trowbridge Reitz GGX:

这里h是测量表面微区的中间矢量,α是表面粗糙度的量度。如果我们将h作为曲面法线和光线方向在不同粗糙度参数下的中间向量,我们将得到以下视觉结果:

粗糙度较低(因此表面是光滑的)时,高度集中的微区在一个小半径上与一半矢量对齐。由于这种高浓度,NDF显示出一个非常亮点。然而,在粗糙的表面上,微空间以更随机的方向排列,你会发现大量的中间向量h与微空间有些对齐(但集中度较低),从而得到更灰色的结果。

在GLSL中,Trowbridge Reitz GGX正态分布函数转换为以下代码:

float DistributionGGX(vec3 N, vec3 H, float a)
{
    float a2     = a*a;
    float NdotH  = max(dot(N, H), 0.0);
    float NdotH2 = NdotH*NdotH;
	
    float nom    = a2;
    float denom  = (NdotH2 * (a2 - 1.0) + 1.0);
    denom        = PI * denom * denom;
	
    return nom / denom;
}

几何函数

几何函数在统计学上近似于其微观表面细节相互遮蔽的相对表面积,从而导致光线被遮挡。

扫描二维码关注公众号,回复: 11571332 查看本文章

与NDF相似,几何函数以材料的粗糙度参数为输入,粗糙度越高,覆盖微区的概率越高。我们将使用的几何函数是GGX和Schlick-Beckmann近似的组合,称为Schlick GGX:

这里的k是α基于几何函数是针对直接光照还是针对IBL光照的重映射(Remapping) :

请注意,因引擎如何将粗糙度转换为α,α值可能而不同。在接下来的章节中,我们将广泛讨论这种重映射如何以及在哪里变得相关。

为了有效地近似几何体,我们需要同时考虑观察方向(几何体障碍)和光方向向量(几何体阴影)。我们可以使用史密斯方法将两者都考虑在内:

使用Smith方法和Schlick GGX作为Gsub,在不同的粗糙度R下,可获得以下视觉外观:

几何函数是[0.0,1.0]之间的乘数,1.0(或白色)测量无微区阴影,0.0(或黑色)完整的微区阴影。

在GLSL中,geometry函数转换为以下代码:

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;
}

菲涅耳方程

菲涅耳方程(读作Freh-nel)描述了被反射的光与被折射的光的比率,它随我们观察表面的角度而变化。光照到表面的那一刻,基于表面到视角,菲涅耳方程告诉我们被反射的光的百分比。根据这个反射比和能量守恒原理,我们可以直接得到光的折射部分。

当直视表面时,每个表面或材质都有一个基准反射率级别,但是当从某个角度观察曲面时,与曲面的基础反射率相比,所有反射都变得更加明显。你可以通过从垂直视角看你的(大概是)木质/金属桌子来检查这个问题,但是从几乎90度的角度看你的桌子,你会发现反射变得更加明显。理论上,如果从完美的90度角观察,所有表面都能完全反射光线。这种现象被称为菲涅耳,用菲涅耳方程描述。

菲涅耳方程是一个相当复杂的方程,但幸运的是,菲涅耳方程可以用菲涅耳-施利克近似近似来近似:

F0表示表面的基本反射率,我们使用所谓的折射率或IOR来计算。正如你在球体表面上看到的,我们越是朝着曲面的掠射角看(一半视角达到90度),菲涅耳和反射就越强:

菲涅耳方程有一些微妙之处。其一,菲涅耳-施利克近似仅适用于电介质或非金属表面。对于导体表面(金属),用折射率计算基底反射率并不合适,我们需要对导体使用不同的菲涅耳方程。由于这是不方便的,我们进一步通过预先计算曲面在0度角的法向入射(F0)时的响应来近似,就像直接观察曲面一样。我们根据Fresnel-Schlick近似,根据视角插值这个值,这样我们就可以对金属和非金属使用相同的方程。

表面在法向入射时的响应,或基底反射率,可以在大型数据库中找到,这些数据库中列出了一些更常见的值,这些值摘自Naty Hoffman的课程笔记:

有趣的是,对于所有的电介质表面,基底反射率永远不会超过0.17,这是例外,而不是规则;而对于导体,基底反射率开始高得多,并且(大部分)在0.5和1.0之间变化。此外,对于导体(或金属表面),基底反射率是有色彩的。这就是为什么F0呈现为RGB三原色来表示(正常入射时的反射率可以随波长变化);这种现象我们只能在金属表面看到。

与电介质表面相比,金属表面的这些特殊属性导致了所谓的金属工作流程。在“金属”工作流中,我们使用一个称为“金属度”的额外参数来编写曲面材质,该参数描述曲面是金属曲面还是非金属曲面。

从理论上讲,一种材料的金属性是二元的:要么是金属,要么不是金属;不可能两者兼而有之。但是,大多数渲染管道允许在0.0和1.0之间线性配置曲面的金属度。这主要是因为材质纹理精度不够。例如,在金属表面上具有小(非金属)灰尘/沙状颗粒/划痕的曲面很难使用二进制金属度值进行渲染。

通过预先计算电介质和导体的F0,我们可以对这两种类型的表面使用相同的菲涅耳-施利克近似,但是如果是金属表面的话就需要对基础反射率添加色彩。我们一般是按下面这个样子来实现的:

vec3 F0 = vec3(0.04);
F0      = mix(F0, surfaceColor.rgb, metalness);

我们定义了一个对于大多数电介质表面近似的基本反射率。这是另一个近似值,因为F0是在最常见的电介质周围的平均值。基本反射率0.04适用于大多数电介质,并且无需编写额外的表面参数即可产生物理上合理的结果。然后,根据表面的金属性,我们要么取介电基底反射率,要么取F0作为表面颜色。因为金属表面吸收所有的折射光,所以它们没有漫反射,我们可以直接使用表面颜色纹理作为它们的基本反射率。

在代码中,Fresnel-Schlick近似转化为:

vec3 fresnelSchlick(float cosTheta, vec3 F0)
{
    return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}

cotheta是曲面法线n和中间h(或视觉(view) v)方向之间的点积结果。

猜你喜欢

转载自blog.csdn.net/tiao_god/article/details/107337277
PBR