
物理上正确的渲染
PBR或基于物理的渲染是基于与光传播的真实理论非常吻合的一种可视化技术。 由于PBR的目的是对光进行物理可靠的模拟,因此与我们之前使用的Phong和Blinn-Fong照明模型相比,它看起来更加真实。 它不仅看起来更好,而且可以很好地逼近真实的物理原理,这使我们(尤其是艺术家)可以基于表面的物理特性来创建材质,而无需诉诸廉价的技巧来使照明看起来逼真。 这种方法的主要优点是,无论光照条件如何,我们创建的材料都将按计划显示,这是其他方法(而不是PBR)无法说的。
但是,PBR仍然是逼真的逼真度(基于物理定律),这就是为什么将其称为物理正确渲染而不是物理渲染的原因。 为了使照明模型在物理上可以被称为正确模型,它必须满足3个条件(不用担心,我们会尽快解决):
- 基于反射微面模型
- 遵守能量守恒定律
- 使用双光束反射率分布函数(BRDF)
在本教程系列中,我们将重点介绍PBR方法,该方法最初是由迪士尼开发的,并适用于Epic Games的实时可视化。 他们的方法基于
金属介电工作流程 (例如,金属工作流程,
找不到更好的翻译-大约是Ed)。该方法有据可查,并在许多流行的引擎中得到了广泛接受,并且看起来令人赞叹。 在本节的最后,我们得到了类似的内容:
请记住,本节中的文章相当高级,因此建议您对OpenGL和着色器照明有很好的了解。 这是学习本节所需的一些知识: 帧缓冲区 , 立方图 , 伽马校正 , HDR和法线图 。 我们还将对数学进行更深入的介绍,但是我保证将尽一切可能尽可能清楚地解释所有内容。
反射微面模型
所有PBR技术都基于微面理论。 该理论认为,高倍率下的每个表面都可以表示为一组称为微面的微观反射镜。 由于表面粗糙度,这些微镜可以沿不同方向定向:
表面越粗糙,其微面的取向就越随机。 这些小镜子的这种布置的结果是(特别是当涉及镜面眩光和反射时),入射光线沿不同方向散射在粗糙表面上,从而导致更宽的镜面眩光。 反之亦然:在光滑的表面上,入射光线更有可能在一个方向上被反射,从而使眩光更小,更锐利:
在微观层面上,没有绝对光滑的表面,但是鉴于微观表面足够小,我们无法在像素空间内对其进行区分,因此我们通过引入粗糙度系数来对表面粗糙度进行统计学上的近似。 使用这个系数,我们可以计算出沿特定矢量方向定向的微面部的比例 ^ h 。 这个向量 ^ h 只是入射光方向之间的中间向量 升 和观察者的方向 v 。 我们在上一堂有关高级照明的课程中讨论过它,我们将其定义为矢量和之比 升 和 v 到所得向量的长度:
h = f r a c l + v | | l + v | |
朝向中值向量方向的微脸越多,镜面反射高光将变得更加清晰明亮。 由于粗糙度系数在0到1之间,因此我们可以从统计角度估算微面的方向:
如您所见,与光滑表面上较小而又尖锐的斑点相比,较高的粗糙度系数值会产生较大的镜面光斑。
节约能源。
使用近似值考虑微面已经进行了某种形式的能量守恒:反射光的能量将永远不会超过入射光的能量(如果表面本身不发光)。 从上图可以看出,随着表面粗糙度的增加,反射光斑增加,但同时亮度降低。 如果所有像素的反射光强度相同,无论光斑大小如何,则粗糙表面将发出更多的能量,这将违反能量守恒定律。 因此,镜面反射在光滑表面上更亮,而在粗糙表面上则变暗。
为了节省能量,我们必须在漫反射和反射镜组件之间进行清晰的分隔。 在那一刻,当光线到达表面时,它分为反射和折射分量。 反射的分量是直接反射的光,不会穿透表面;我们知道它是光的镜像分量。 折射成分是穿透表面并被其吸收的光-我们将其称为光的散射成分。
但是有一些与光吸收有关的细微差别-一旦光接触到表面,它就不会立即发生。 从物理学的过程来看,我们可以将光描述为光子束,其能量沿直线移动,直到由于与障碍物碰撞而失去所有能量。 每种材料均由可与光线相互作用的微粒组成,如下图所示。 这些粒子在每次碰撞中吸收光的部分或全部能量,将其转化为热量。
在一般情况下,并非所有能量都被吸收,并且光继续(主要)在随机方向上散射,在此方向上,光再次与其他粒子碰撞,直到能量用尽或再次离开表面。 因此,表面开始重新发射光线,以观察到的(漫射)表面颜色的形式做出贡献。 使用PBR,我们做出简化的假设,即所有折射光在较小的影响区域内被吸收和散射,而忽略了离开该区域一定距离的表面散射光的影响。 考虑到这一点的特殊着色器技术(称为次表面散射技术)极大地提高了皮革,大理石,蜡等材料的视觉质量,但性能却很昂贵。
当光线在金属表面折射和反射时,还会出现其他细微差别。 金属表面与光的相互作用不同于非金属 (即电介质)的相互作用。 它们遵循相同的折射和反射定律,但有一个例外:所有折射光都被表面吸收而没有散射,仅保留镜面反射光。 换句话说,金属表面没有漫反射的颜色。 由于金属和电介质之间存在明显的差异,因此它们将在PBR输送机中进行不同的处理,我们将在本文中进一步介绍。
反射光和折射光之间的差异使我们对能量守恒有了另一种观察:它们的值是互斥的。 反射光的能量不能被材料吸收。 因此,以折射光的形式被表面吸收的能量是考虑反射光之后的剩余能量。
我们使用该比率,首先将反射部分计算为表面反射的入射光线能量的百分比,然后再将直接来自反射的折射光的分数计算为:
float kS = calculateSpecularComponent(...); // / float kD = 1.0 - kS; // /
这样,由于能量守恒定律,我们可以了解反射部分和折射部分的含义。 使用这种方法,折射(漫射)或反射部分都不会超过1.0,从而确保它们的总能量不超过入射光能的值,而在以前的课程中我们没有考虑这一点。
反射方程
上面的内容将我们引向所谓的渲染方程式 :一个非常聪明的人发明的复杂方程式,今天它是模拟光照的最佳模型。 PBR严格遵循此方程式的更具体版本, 即反射方程式 。 为了更好地理解PBR,首先必须完全了解反射方程式,这一点很重要:
Lo(p, omegao)= int limits Omegafr(p, omegai, omegao)Li(p, omegai)n cdot omegaid omegai
起初它看起来很吓人,但是我们将逐步地将其分解,然后您将看到它逐渐变得有意义。 为了理解这个方程,我们将不得不更深入地进行辐射测量。 放射线学是测量电磁辐射(包括可见光)的科学。 我们可以使用几种辐射量来测量照明度,但是我们只会使用与反射方程式相关的一个量度,即能量发光度(英语辐射度),此处用字母L表示。EI用于量化光的强度或强度,来自某个方向。 反过来,EJ是几个物理量的组合,因此我们更容易想象它,我们将分别关注每个物理量。
辐射通量
辐射通量( \皮皮 )是光传输能量的功率,以瓦特为单位。 光的总能量由许多不同波长的项组成,每个项对应于它自己的光谱颜色。 在这种情况下,光源发出的能量可以表示为所有这些波长的函数。 390nm至700nm的波长构成了光谱的可见部分,也就是说,人眼可以感知此范围内的辐射。 在下图中,您可以看到组成日光的不同波长的能量值:
对于所有波长,辐射通量均对应于该函数的图下面积。 在计算机图形学中直接使用光的波长作为输入是不切实际的,因此我们求助于辐射通量的简化表示,而不是使用所有波长的函数,而是使用称为RGB的三元组颜色(或通常称为照明的颜色)。 这样的观点会导致信息丢失,但总体而言会稍微影响最终的画面。
立体角
立体角表示为 omega 给我们投影到单位球体上的图形的大小或面积。 您可以将其想象为一个具有以下数量的方向:
假设您位于球体的中心,并朝着图的方向看。 最终轮廓的大小将是一个立体角。
辐射强度
辐射强度测量的是每个立体角的辐射通量,或由立体角定义的每单位面积的光源强度。 例如,对于在所有方向均等发射的全向光源,辐射力是指每个特定区域(立体角)的光能:
描述辐射强度的等式如下:
I= fracd Phid omega
,其中I是每个立体角的辐射通量f d omega
了解了辐射通量,力和立体角,我们可以描述能量亮度方程,该方程描述区域A中的总观测能量,受力对光线的立体角O的限制 \皮皮
L= fracd2 PhidAd omega cos theta
能量亮度是取决于入射光角度的区域中光的辐射量。 theta (光的方向与表面法线之间的角度) cos theta :沿表面发射时光线较弱,而与表面垂直时则较强。 这类似于我们在照明基础知识教程中对漫射光的计算,因为 cos theta 无非就是光的方向和表面的法线向量之间的标量积:
float cosTheta = dot(lightDir, N);
能量亮度方程式对我们非常有用,因为它包含了我们感兴趣的大多数物理量。 如果假设立体角ω和面积A为无穷小,则可以使用EE来测量空间中每一点的一束光线的通量。 这将使我们能够计算作用在单个点(片段)上的单个光线的EI。 我们实际上翻译了立体角 omega 在方向矢量 omega 和 到这一点 p 。 因此,我们可以直接在着色器中使用EI来计算单个光线对每个片段的贡献。
实际上,当涉及到EE时,我们通常会对入射在点p上的所有入射光感兴趣,p是整个EE的总和,被称为辐照度。 了解了EI和辐射,我们可以返回到反射方程:
Lo(p, omegao)= int limits Omegafr(p, omegai, omegao)Li(p, omegai)n cdot omegaid omegai
现在我们知道 L 渲染方程中的p是表面p上某个点的EI和入射光的一些无限小立体角 omegai ,可以将其视为输入方向向量 omegai 。 请记住,能量乘以 cos theta -光的入射方向与表面法线之间的角度,由乘积的反射方程表示 n cdot omegai 。 反射方程式计算反射EI的总和 Lo(p, omegao) 点数 p 朝 ωo ,这是观察者的输出方向。 否则: Lo 测量点的反射辐照度 p 如果从 omegao 。
由于反射方程基于辐射,即所有入射辐射的总和,因此我们不仅测量一个入射光方向的光,而且还测量半球内所有入射光方向的光 \欧米茄 集中于 p 。 可以描述为沿表面法线定向的半球 n :
为了计算区域内所有值的总和,或者在半球的情况下计算体积,我们在所有传入方向上对方程进行积分 d omegai 在半球内 \欧米茄 。 由于对于渲染方程和反射方程都没有解析解,因此我们将在数值上求解积分。 这意味着我们将获得半球反射方程离散小步的结果 \欧米茄 并根据步长进行平均。 这称为黎曼和 ,我们可以用以下代码大致表示:
int steps = 100; float sum = 0.0f; vec3 P = ...; vec3 Wo = ...; vec3 N = ...; float dW = 1.0f / steps; for(int i = 0; i < steps; ++i) { vec3 Wi = getNextIncomingLightDir(i); sum += Fr(P, Wi, Wo) * L(P, Wi) * dot(N, Wi) * dW; }
每个离散步骤的dW可以认为是 d omegai 在反射方程中。 数学上 d omegai 是计算积分的微分,尽管它与代码中的dW不相同(因为这是Riemann和的离散步长),但为便于计算,我们可以将其视为这样。 请记住,使用离散步长将始终为我们提供近似值,而不是积分的确切值。 细心的读者会注意到,我们可以通过增加步数来提高黎曼和的精度。
反射方程式将所有入射光方向的辐射求和 omegai 半球 \欧米茄 达到了重点 p 并返回反射光量 Lo 对观众。 入射辐射可以来自我们已经熟悉的光源,也可以来自确定每个入射方向EI的环境图,我们将在IBL教程中进行讨论。
现在左边唯一的未知数是 fr ,称为BRDF函数或双光束反射率函数 ,该函数根据表面材料的属性缩放(或称重)入射辐射的值。
BRDF
BRDF是一种接受入射光方向的功能。 omegai ,向观察者的方向 omegao 垂直于表面 n 和参数 一 ,即表面粗糙度。 BRDF估计每个单独的光束多少 omegai 考虑到其材料的特性,有助于不透明表面的最终反射光。 例如,如果表面完全光滑(几乎像镜子),则BRDF函数将为所有入射光线返回0.0 omegai 除了与光束具有相同角度(反射后)的角度以外 omegao 为此,该函数将返回1.0。
BRDF根据前面提到的微面理论来估算材料的反射和折射特性。 为了使BRDF在物理上具有合理性,它必须遵守能量守恒定律,也就是说,反射光的总能量绝不能超过入射光的能量。 从技术上讲,Blinn-Fong模型被视为接受相同条件的BRDF omegai 和 omegao 在入口处。 但是,Blinn-Fong模型在物理上不正确,因为它不能保证遵守能量守恒定律。 有几种物理上正确的BRDF可以近似表面对光照的响应。 但是,几乎所有的实时图形管道都使用BRDF,即Cook-Torrance BRDF 。
Cook-Torrens BRDF包含漫反射和镜像部分:
fr=kdflambert+ksfcook−torrance
在这里 kd -入射光能的折射分数, ks -反映出来。 BRDF的左侧包含方程式的扩散部分,在此表示为 flambert 。 这就是所谓的兰伯特散射。 它与我们用于漫射照明的相似,并且是恒定的:
flambert= fracc pi
在哪里 c -反照率或表面颜色(漫反射表面纹理)。 除以 pi 归一化散射光所需的量,因为先前指示的包含BRDF的积分乘以 pi (我们将在IBL教程中对此进行介绍)。
您可能会对这种Lambertian散射与我们之前使用的漫射照明的表达式非常相似感到惊讶:表面的颜色乘以表面法线与光的方向之间的标量积。 标量乘积仍然存在,但是可以从BRDF推断出来,因为 n cdot omegai 在积分中 Lo 。
对于BRDF的扩散部分,有各种方程式看起来更逼真,但在性能方面却更为昂贵。 此外,正如史诗游戏所得出的结论:朗伯散射足以满足大多数实时渲染目的。
Cook-Torrens BRDF的镜面部分进行了一些改进,其描述为:
fcook−torrance= fracDFG4( omegao cdotn)( omegai cdotn)
它由三个函数和分母中的标准化系数组成。 字母D,F和G中的每一个代表某种类型的函数,该函数近似于表面的反射特性的某些部分。 它们被称为正态分布函数(NDF),菲涅耳方程和几何函数:
- 正态分布函数:基于表面粗糙度,估计沿中值矢量定向的表面微面的数量; 这是逼近微脸的主要功能。
- 几何函数:描述微面的自遮蔽特性。 当表面相当粗糙时,表面的某些微面可能与其他微面重叠,从而减少了表面反射的光量。
- 菲涅耳方程:描述不同角度的表面反射系数。
这些功能中的每一个都是其物理等效项的近似值,并且对于它们而言,存在各种实现方式,其目的是更精确地近似于基础物理模型。 有些可以提供更实际的结果,而另一些则在效果方面更有效。 Epic Games的Brian Caris对不同类型的逼近进行了大量研究,您可以在此处了解更多信息。 我们将使用与Epic Games虚幻引擎4中相同的功能,即: Trowbridge-Reitz GGX用于D, Fresnel-Schlick近似用于F, Smith的Schlick-GGX用于G。
正态分布函数
正态分布函数D统计地逼近沿着中值矢量精确定向的微面的相对表面积 h 。 考虑到一些粗糙度参数,有许多NDF决定了微面整体对齐的统计近似值。 我们将使用一种称为Trowbridge-Reitz GGX的产品:
NDFGGXTR(n,h, alpha)= frac alpha2 pi((n cdoth)2( alpha2−1)+1)2
在这里 h 是中位数向量, alpha -表面粗糙度值。 如果我们选择 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; }
几何功能
几何函数从统计学上近似于其微观不规则重叠的相对表面积,从而防止了光线的穿透。
与NDF一样,几何函数接受表面粗糙度系数作为输入,在这种情况下表示以下含义:较粗糙的表面将具有遮盖微表面的可能性更高。 我们将使用的几何函数是GGX和Schlick-Beckmann近似的组合,被称为Schlick-GGX:
GSchlickGGX(n,v,k)= fracn cdotv(n cdotv)(1−k)+k
在这里 k 是重新指定 alpha 取决于我们将几何函数用于直接照明还是IBL照明:
kdirect= frac( alpha+1)28
kIBL= frac alpha22
请注意,值 alpha 可能会有所不同,具体取决于您的引擎如何将粗糙度转化为 alpha 。 在以下课程中,我们将详细讨论这种重新分配的方式和位置。
为了有效地近似几何形状,我们需要同时考虑观察方向(重叠的几何形状)和光的方向矢量(几何形状自阴影)。 我们可以使用Smith方法来考虑这两种情况:
G(n,v,l,k)=Gsub(n,v,k)Gsub(n,l,k)
将Smith方法与Schlick-GGX一起使用 Gsub 给出以下具有不同粗糙度R的图片:
几何函数是[0.0,1.0]之间的因数,其中白色(或1.0)表示没有微影的阴影,而黑色(或0.0)则表示微脸的全阴影。
在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; }
菲涅耳方程
菲涅耳方程描述了反射光和折射光的比率,该比率取决于我们观察表面的角度。 当光射到表面上时,菲涅耳方程式会根据我们看到该表面的角度为我们提供反射光的百分比。 从这种反射比和能量守恒定律,我们可以直接获得光的折射部分,该部分将等于剩余能量。
每种表面或材料都有一定的基本反射率 ,直接观察表面时会观察到,但是如果以一定角度观察表面, 所有反射都会变得更加明显。 您可以先垂直看您的木桌或金属桌子,然后再以接近90度的角度看一下,以此来验证自己。 您将看到反射变得更加明显。 从理论上讲,所有表面以90度的理想角度完全反射光。 该效应称为菲涅耳, 由菲涅耳方程描述。
菲涅耳方程非常复杂,但是幸运的是,可以使用菲涅耳-施里克近似将其简化:
FSchlick(h,v,F0)=F0+(1−F0)(1−(h cdotv))5
F0 代表表面的基本反射率,我们使用称为折射率或IOR (折射指数)的方法进行计算,并且,如您在球体表面上所看到的,观察方向越接近可见球体的边界(观察方向与中间值之间的夹角) 90 ), , , :
, . , - . (), , . , ( F0 ) ( 0 , ) -, , .
. , , :
: 0.17, , , ( ) 0.5 1.0. , “”, F0 RGB ( ).
, metallic workflow: , (metalness), , .
: , ; , . , 0.0 1.0. - , , , . , .
F0 , , - , , . :
vec3 F0 = vec3(0.04); F0 = mix(F0, surfaceColor.rgb, metalness);
, . , F0 . 0.04 . , , , F0 . , , .
- :
vec3 fresnelSchlick(float cosTheta, vec3 F0) { return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); }
cosTheta .
-
BRDF - :
Lo(p,ωo)=∫Ω(kdcπ+ksDFG4(ωo⋅n)(ωi⋅n))Li(p,ωi)n⋅ωidωi
. , , F . ks , , ks 。 , :
Lo(p,ωo)=∫Ω(kdcπ+DFG4(ωo⋅n)(ωi⋅n))Li(p,ωi)n⋅ωidωi
, PBR. , , . , , .
PBR
, PBR, , , PBR. , PBR, . , : , .
, PBR, :
: , . , . , ; .
: , , . , , .
: . , PBR-, , : .
: , . . , . PBR- , , (1.0 — ) .
AO (ambient occlusion) : AO . , , . AO , . . , 3D-.
. PBR, , . , PBR, PBR-, , , .
相关资料
- Background: Physics and Math of Shading by Naty Hoffmann: , , ; PBR, must-read .
- Real shading in Unreal Engine 4 : PBR, Epic Games Unreal Engine 4. PBR, , .
- Marmoset: PBR Theory : PBR. , , , .
- Coding Labs: Physically based rendering : , PBR.
- Coding Labs: Physically Based Rendering — Cook–Torrance : BRDF -
- Wolfire Games — Physically based rendering : PBR Lukas Orsvärn.
- [SH17C] Physically Based Shading : shadertoy (: ) Krzysztof Narkowi, PBR.