图形渲染——PBR(PBS)基于物理的渲染

//====================================

打一个标记在这里,因为最近看了Games202的课程,有关BRDF的部分希望进行一些补充就不单独开新的部分了。要想了解Games202课程关于PBR的笔记,推荐一个博主的文章(GAMES202 笔记 -Real-Time Physically-Based Materials_奇迹小缘的博客-CSDN博客),我个人觉得很全,不过可能还是不好理解,给我的感觉就是将老师上课的东西直接摘下来了,怎么理解没有详细说说,现在我要加上我自己的理解,也欢迎大佬指正。

//====================================

本篇专项讲解基于物理的渲染PBR(PBS),到底最后一个所学是Rendering还是Shadering并不重要,因为指代的都是一个东西。

我也是在对了比好多资料之后给出本篇的写作内容,下边就直接开始吧。

一、PBR简介

基于真实世界物理光线与材质界面交互过程建立起来的渲染理论。

PBR的特色就是深度还原一束光,从发出到达材质界面,然后分为反射与折射(可能会再次射出进行漫反射),呈现最终综合的光照渲染结果。

二、必要条件

要确定为PBR,需要满足以下三个条件:
1.基于微表面模型;

2.能量守恒;

3.使用基于物理的BRDF;

从某种程度上来说,使用基于物理的BRDF也就满足了前两条,因为基于物理的BRDF就是建立在前两条基础上推导、模拟出的渲染方程。

三、微表面模型

鸿篇巨制有很多,但我倾向于用最简短最白话的叙述来表述我的观点。

所谓微表面就是相对我们肉眼可见的宏观表面提出的,它能反映材质微小表面的粗糙起伏情况(法线的不规律分布)。在这个部分,我们只做一件事:
使用表面粗糙度估算半角向量与宏观法向量的偏离程度(一致性概率)。

四、能量守恒

出射光能量不能大于入射光总能量(自发光除外)。

这就是我们要表达的能量守恒观点,具体解释一下。光与界面接触后,分为反射光与折射光两个部分,其中反射光直接离开表面形成高光,折射光进入材质内部,与内部电子等作用产生能量转化,可能会有部分光再次射出材质表面,成为漫反射部分。也就是说漫反射实际是折射光的一部分(金属吸收所有折射光,所以没有漫反射)。因此:

总能量=反射光能量+折射光能量=反射光能量+(漫反射能量+)材质吸收能量。

通常情况下PBR会结社折射能量被完全吸收,不再进行漫反射。更高级的次表面反射确模拟了光重新离开材质,但性能开销较大。

五、反射方程(渲染方程)

这是本文的重点,我们也可以从中找到与前边的对应关系。

先直接看一下这个方程的表达式:

L_{o}(p,w_{o})=\int f_{r}(p,w_{i},w_{o})L_{i}(p,w_{i})n\cdot w_{i}dw_{i}

先拆解这个公式

f_{r}(p,w_{i},w_{o})表示BRDF,双向反射分布函数

L_{i}(p,w_{i})n\cdot w_{i}方向w_{i}上的入射光在p点的光照贡献(总光能量)

对于第二部分总光能量,有很多资料讲得很模糊或者又太深奥,会涉及很多光学理论,又是积分又是微分啥的,对初学者并不友好。当然如果能从根源上理解这个问题当然是极好的,不过我还是想表达我简单粗暴地观点,这个地方我的理解就是:
光从光源发出后,经过衰减与角度投射后到达观察表面p的光能量,具体的内容可以参考我在专栏文章《D3D12学习笔记——入射光》对入射光衰减的表述。

所以L_{i}(p,w_{i})n\cdot w_{i}实际就是总光能量,考虑了衰减与投射之后真实到达材质界面的总能量。

现在来看比较复杂的第一项BRDF,也是本篇的重点。

BRDF

双向反射分布函数,是一个计算高光反射+漫反射分别作用于总光能量占比的函数(加权值)。

还是给出其表达:
f_{r}=k_{d}f_{lambert}+k_{s}f_{specular}

包含了两个部分,漫反射与高光反射,漫反射部分比较简单:
k_{d}为折射占比,表示入射总光能量被折射的权重值,对应的k_{s}为反射光占总光能量权重,根据能量守恒k_{d}+k_{s}=1

对于f_{lambert}表示折射光部分参与漫反射的比率,换句话说就是对总光能量的二次折减:

漫反射=总光能量X折射占比X漫反射占比

其表达如下:f_{lambert}=\frac{M_{d}}{\pi }使用π是因为后边还有积分。

M_{d}表示材质的漫反射颜色(Albedo),也可以形象的理解为材质表面颜色(定义的对RGB的吸收比率)。

这个部分使用M_{d}也就与我们之前基于勃朗特的漫反射模型对应起来了:

C_{d}=M_{d}B_{L}(n\cdot L)

可以看出如果把积分考虑进来,传统的兰伯特也还是有可取之处的,唯一的差异性就是对系数k_{d}的忽视,也就是说传统兰伯特模型并不是能量守恒的。

解决了漫反射项,我们再来看看最为复杂的高光反射项,这个地方实际有很多种实现,这里我们解释Cook-Torrance的高光项,因为这在实时渲染管线中使用最广。

f_{specular}=f_{cook-torrance}=\frac{DFG}{4(n\cdot w_{o})(n\cdot w_{i})}

分母部分相信没啥好说的,法线n,入射方向wi和出射方向wo.

重点看看分子部分:

D:法线分布函数

GGX模型

这也是我们使用微表面模型的原因,即使用表面粗糙度估算半角向量与宏观法向量的偏离程度(一致性概率)。这正是我们使用微表面的目的,具体的计算方法如下:
D(n,h,roughness)=\frac{roughness^{2}}{\pi ((n\cdot h)^{2}(roughness^{2}-1)+1)^{2}}

roughness是0-1区间的数,越小表示越光滑;

h为半角向量;

n为法向量;

他的一个性质就是long tail长尾效果,就是从中心到边界是渐变的,会有一个光晕的效果:

 //=============

来自Games202

Beckmann模型

只有两个变量,粗糙度\alpha(roughness)和角度\theta _{h}(宏观法线方向与半程向量的夹角)

 GTR模型

Generalized Trowbridge Reitz是对GGX的拓展,下边是他的表达式,看上去是很简洁的,并且当\gamma比较大的时候能很好的拟合Beckmann模型,但是最关键的一个问题是分子c,我查了资料,这个c还是由粗糙度\alpha(roughness)和角度\theta _{h}(宏观法线方向与半程向量的夹角)表达,但是一直没找到统一表达,这可能就是他比较难使用的原因。

 

F:菲涅尔项

我在专栏文章《D3D12学习笔记——光照》部分介绍过这个:

F=F_{0}+(1-F_{0})(1-(n\cdot v))^{5}

这里要注意一下,我看到了很多不同的版本,主要在于n\cdot v,这里使用的是法线与视向量,也有使用半角向量与视向量h\cdot v,也有使用法线与光向量n\cdot L,因为这本身就是一个近似(石里克近似),所以我觉得差异不大,应该来说都是可以的,但是这项本身的定义是:不同观察方向上,反射光比率不同。因此使用视向量与法向量是比较合理的。

G:几何遮挡

这个函数用于模拟不平整微表面的相互遮挡,主要是指1.对视线的遮挡;2.对光线的遮挡。这两点的基本思路是一样的,因为都把视线v和光线L当做向量来处理,处理的基本表达式为:

G(n,d,k)=\frac{n\cdot d}{n\cdot d(1-k)+k}

其中d可以表示视线v或者光线L,表述微表面对视线或者光线的遮挡导致的阴影占比。那么要同时考虑视线与光线,则要进行整合(乘积):

遮挡视线:G(n,v,k)=\frac{n\cdot v}{n\cdot v(1-k)+k}

遮挡光线:G(n,L,k)=\frac{n\cdot L}{n\cdot L(1-k)+k}

则最终的几何遮挡函数:

G=G(n,v,k)\cdot G(n,L,k)

上边的式子中:n表示表面法线,v为视线向量,L为光线向量,对于k:

k_{direct}=\frac{(roughness+1)^{2}}{8}适用于直接光照

k_{imageBasedLight}=\frac{roughness^{2}}{2}适用于光照贴图(来源于场景烘焙等)

//=============

来自Games202

使用不同的NDF对G会有一定的影响,因为N的预测实际也就是微表面朝向预测,对于光线和视线的遮挡就会有影响,以下是差异:

 但是无论如何都是满足基本观察规律的,那就是角度为0的时候,此时半程向量与法向量一致,相当于没有遮挡,结果都是1。

来自Games202

Missing Energy

这个部分Games202讲解比较难理解,我看的笔记更多的像是课堂记录,没有个人理解,我想分享一下自己的理解,希望有大神帮我指正。

我们常说能量守恒,到目前为止,看上去我们这个过程就是能量守恒的,其实不然,因为我们考虑G的时候是决定光线不被遮挡,视线也不被遮挡的占比,来决定光线的出射。但是实际上,光线经过多次反射还是会射出来的,这就会导致能量不守恒,使得如果表面粗糙的时候颜色会变暗。

先解释基本思路:

既然是因为遮挡导致多次反射,这部分能量只使用G会被丢失,导致BRDF计算值偏小,那么就想办法把他加回来。这个办法课程介绍叫做Kulla-Conty。

方程如下:

解释:

1).使用入射光照总能量为1,(常数1,无论乘积还是积分都不会导致结果有误,因为我们只是算一个比例)

2).积分式计算的就是对渲染方程(无光照,仅考虑BRDF在整个半球面的积分结果),也就是说计算了对整个半球面来说光的出射比例;

3).既然积分式计算的是出射比例,换句话讲1-E(\mu _{o})就是要参与后续反射的能量比例,且由于光路是可逆的,因此真正被遮挡,要参加后续反射的能量占比为:
c(1-E(\mu _{o}))(1-E(\mu _{i}))

c为归一化的系数(可以是常量和函数)

4).计算能量损失的BRDF

 注意分母的平均,对他的求解是使用split sum一种打表的方式:这个二重积分只需要一个二维表(粗糙度与角度)

以上讨论建立在初始光照能量为1的情况,并且没有颜色值,如果有颜色值那么颜色本身就是一种吸收(损失),那么我们不妨换个思路来考虑:将每次反射出来的能量进行累加,因为要进行累加,并且弹射角度很多,所以使用平均才有意义:

1.直接能看到的能量:color*Favg * Euo

2.弹射一次能看到的能量:color*Favg * (1-Euo) * FavgEavg

.....

3.弹射k次能看到的能量:color*Favg ^k* (1-Euo))^k * FavgEavg

那么所有看到能量项求和

color*\frac{F_{avg}E_{avg}}{1-F_{avg}(1-E_{avg})}

其中:\frac{F_{avg}E_{avg}}{1-F_{avg}(1-E_{avg})}因为我们使用的是总能量为1,所以这个数值位于0-1之间,真正表示了出射能量的占比,也就是真正的BRDF,而不是简单的基于G一次遮挡的考量。

 这里边我们要计算两个平均值:
1.一个是出射能量的平均值,上边说了使用打表的方法;

2.菲涅尔项的平均值:不管入射角多大,平均每次反射会有多少能量反射。平均菲涅尔项的计算就是计算在所有角度下,菲涅尔项的平均值:

因此,我们考虑Miss Energy的正确做法,或者叫做光线经过多次弹射(而非一次的G遮挡)的计算方式,就是计算F_{avg}E_{avg},用来估算最终多次弹射出来的能量占比,这才是真正的BRDF项,他将DFG考虑进平均值里边,在满足求极限得到真正的BRDF值。但是计算效率肯定是不太好的,所以了解即可。

我也不知道我理解得是否准确,欢迎大佬来指正,并且如果我错了,我后边会修改。这里要注意一件事,Games202中闫老师着重批评了一件事就是使用一个diffuse来填补能量损失的部分,认为这是完全错误的。确实,从物理的角度来说真的是错误的,但是这样很快,所以很多地方给出了下边的方程:
L_{o}(p,w_{o})=\int(k_{d}\frac{M_{d}}{\pi }+k_{s}\frac{DFG}{4(n\cdot w_{o})(n\cdot w_{i})})B_{L}n\cdot w_{i}dw_{i}

要注意ks表示反射光的占比,而F实际计算就是针对反射光占比(考虑了不同观察角度),因此这里不需要单独乘ks了,正确的表达为:
L_{o}(p,w_{o})=\int(k_{d}\frac{M_{d}}{\pi }+\frac{DFG}{4(n\cdot w_{o})(n\cdot w_{i})})B_{L}n\cdot w_{i}dw_{i}

注意B_{L}n\cdot w_{i}为入射光沿方向w_{i}投射到材质界面的总光能量。也就是说我们计算的漫反射与高光反射实际都是在计算权重占比,是基于物理材质的结果占比。

实际上,这种强加diffuse保持能量守恒是不正确的,会导致产生一些发光的brdf(结果大于1),但是它快啊。换句话说,如果你使用平均反射能量与平均菲涅尔计算能量损失,就不必按照上式强行补上diffuse,如果只考虑一次G,那么上式虽然不是物理正确的,但是起码更加能量守恒。一个好的思路是让diffuse项成为自适应的,既简单又满足能量守恒,希望以后可以出现。

补充Games202考虑可见性的渲染方程:

L_{o}(p,w_{o})=\int L_{i}(p,w_{i})f_{r}(p,w_{i},w_{o})(n\cdot w_{i})V(p,w_{i})dw_{i}

注意看这里的V(p,w_{i})L_{i}(p,w_{i})具有相同的自变量,实际在直接光照中他就是合在一起的。在Games202中考虑全局光照,实时渲染关节分开来看(实际光照+是否可见),两项的综合有利于我们区分精确光源直接光照和环境光照的影响(贡献)。

OK,以上就是我对于BPR的认识,当然如果你接触过基于物理的引擎,比如Unreal,Unity等,就会明白我们在对材质进行建模时大体指定一些描述材质的参数,而这实际是Disney's principle BRDF,这部分也可以在Games202课程的后半程找到,他虽然不是物理正确的,但是对于设计者来说非常友好,但到底层应该也是为了用于我们上述方程的输入。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值