源码分析学习记录(9)——PBR材质

2021SC@SDUSC

Dust3D中的材质采用PBR模型。PBR就是Physically-Based Rendering的缩写,意为基于物理的渲染。它提供了一种光照和渲染方法,能够更精确的描绘光和表面之间的作用。由于PBR基于物理的渲染旨在以物理上合理的方式模拟光,因此与我们的原始照明算法(如 Phong 和 Blinn-Phong)相比,它通常看起来更逼真。因为它非常接近实际物理,我们可以根据物理参数创作表面材料。它不仅擅长用来表现非常写实的材质,同时也能用来处理风格化的资源。

文章目录

  • Microfacet Model
  • Energy Conservation
  • 反射方程
  • BRDF
  • 菲涅尔方程
  • PBR材质

Microfacet Model

现实当中大多数物体的表面都会有非常微小的缺陷:微小的凹槽、裂缝、几乎肉眼不可见的凸起,以及在正常情况下过于细小以至于难以使用普通映射表现出来的细节。尽管这些微观的细节几乎难以用肉眼观察到,但是他们仍然影响着光的扩散和反射。
微表面处的细节对反射的影响最容易被观察到,当平行光照射到粗糙表面时会分散开来,也即是每条光线都照射到了物体表面上朝向不同的部分,导致更广泛的镜面反射。
在这里插入图片描述

没有任何表面在微观层面上是完全光滑的,但由于这些微表面足够小,我们无法在每个像素的基础上区分它们,但我们在统计上近似表面的微表面粗糙度,给定粗糙度范围。基于表面的粗糙度,我们可以计算出与某个向量大致对齐的微表面的比率 h。这个向量 h 是个半程向量(Halfway Vector),即光线与视线夹角一半方向上的一个单位向量:
源码分析学习记录(9)——PBR材质_第1张图片

微表面的细节对于任何材质都是个非常重要的特质,就像真实世界中就有着各种各样的微表面。光泽度贴图并不是一个新概念,但因为微表面的细节对光照的反射具有如此重要的影响,所以它在PBR中占据了一个关键位置。所有的 PBR 技术都基于微平面理论。该理论描述了任何微观尺度的表面都可以用微小的完全反射镜来描述,称为微表面。根据表面的粗糙度,这些微小的镜面的对齐方式可能会有很大差异。

Energy Conservation

如果每个像素的镜面反射强度相同(无论镜面反射形状的大小如何),则较粗糙的表面会因为具有更多像素的微表面而发出更多的能量,这违反能量守恒原理,所以在光滑的表面上看到的镜面反射更强烈,而在粗糙的表面上则更暗淡。光线照射到表面的那一刻,会分成一个折射部分和一个反射部分,折射部分是进入表面并被吸收的剩余光,反射部分是直接被反射而不进入表面的光。

源码分析学习记录(9)——PBR材质_第2张图片
从物理学中,我们知道光可以被描述为一束能量,它不断向前移动直到失去所有能量。光束失去能量的方式是碰撞。一般来说,并不是所有的能量都被吸收,大部分光会继续分散在随机方向上,与其他粒子碰撞直到它的能量耗尽或再次离开表面。从表面重新出现的光线对人眼观察到的表面颜色有贡献。在PBR中,我们假设所有折射光都会在非常小的影响区域被吸收和散射,忽略从远处离开表面的散射光线的影响——这一技术称为次表面散射,他可以显著改善皮肤、大理石或蜡等材料的视觉质量,但会以性能为代价。

金属表面遵循相同的反射和折射原理,但所有折射光都被直接吸收而不会散射。这意味着金属表面只留下反射光或镜面光,而不显示漫反射光。由于金属和非金属之间的这种明显区别,它们在 PBR 中的处理方式不同。

我们首先通过计算反射、入射光能量百分比的镜面反射率来保持能量守恒关系。然后根据镜面反射率直接计算折射光的分数。这样我们既知道入射光的反射量,也知道入射光的折射量,同时遵守能量守恒原理。鉴于这种方法,折射/漫射和反射/镜面反射的贡献不可能超过1.0,这可以确保它们的能量总和永远不会超过入射光能量。

float kS = calculateSpecularComponent(...); // reflection/specular fraction
float kD = 1.0 - kS;                        // refraction/diffuse  fraction
vec4 evaluateLightMaterialColor(in vec4 normal)
{
   
    // 初始化为黑色
    vec3 finalColor = vec3(c_zero, c_zero, c_zero);

    // 将黑色更新为基础环境色
    finalColor += qt_Light.ambient.rgb * qt_Material.ambient.rgb;

    // 添加漫反射组件
    vec4 lightDir = vec4( normalize(qt_Light.direction), 0.0 );
    float diffuseFactor = max( c_zero, dot(lightDir, normal) );
    if(diffuseFactor > c_zero)
    {
   
        finalColor += qt_Light.diffuse.rgb *
                      qt_Material.diffuse.rgb *
                      diffuseFactor *
                      qt_Material

你可能感兴趣的:(Dust3D代码分析报告,材质)