PBR中BRDF的实现
文章目录
- PBR中BRDF的实现
- 白说
- 辐射度量学(Radiometry)
- Radiant flux
- Radiant Intensity
- 立体角(Solid Angle)
- 圆心角
- Irradiance
- Radiance
- 对比Irradiance与Radiance
- 引入BRDF
- 引入反射方程
- 实现BRDF
- 漫反射部分
- 镜面反射部分
- 正态分布函数(Normal Distribution Function)
- 菲涅尔方程(Fresnel Rquation)
- 几何函数(Geometry Function)
- Cook-Torrance反射方程
- 参数的输入
- 各种纹理
- kd、ksk_d、k_skd、ks
PBR中BRDF的实现
白说
- PBR, Physically Based Rendering, 基于物理的渲染,在一定程度上基于物理原理的渲染技术
- PBR仍是对现实世界的一种近似
- BRDF,Bidirectional Reflectance Distribution Function,双向反射分布函数,是PBR的重要组成部分
- 想要理解BRDF,首先要理解辐射度量学中的四个概念
辐射度量学(Radiometry)
- 主要理解radiant flux(辐射通量)、radiant intensity(辐射强度)、irradiance(辐射照度)和radiance(辐射率)这四个概念;对应的中文名字如果感觉蹩脚,可以忽略
Radiant flux
- 一个光源单位时间所输出的能量,符号Φ,Φ=dQdtΦ = \frac{dQ}{dt}Φ=dtdQ,单位瓦特(W)
- 单位时间的能量其实就是功率,从他的单位是瓦特也能看出来,因此他表示的就是功率
- 但是,后面三个概念提到的“能量”指的都是这个功率,而非真正的能量——单位焦耳(Q)。这种称呼只是是习惯上的叫法
- 为什么用“功率”代替“能量”?不仅不严谨,而且还习惯性的不严谨
- 因为在研究光的能量传播时,不仅与空间相关,而且与时间相关。在这里,为了降低问题的复杂度,只考虑空间;而在时间这个维度上,把能量单位化就可以不用再考虑时间了;将能量在时间上单位化,就变成了功率,所以“功率”就成了辐射度量学中的“能量”
Radiant Intensity
- 一个光源单位立体角发出的能量, 符号I,I(ω)=dΦdωI(ω) = \frac{dΦ}{dω}I(ω)=dωdΦ,这里的“能量”指的就是上面说的Radiant flux
立体角(Solid Angle)
- 如果不知道立体角是个啥,可以先看看圆心角
圆心角
- 圆心角θ等于弧长除以半径,θ=lrθ = \frac{l}{r}θ=rl
- 圆心角表示的是二维空间中的一个角度
- 类比圆心角,但把空间变换到三维,立体角ω等于球面上的一块面积除以半径的平方,ω=Ar2ω = \frac{A}{r^2}ω=r2A(A表示单位球上截面面积)
- 立体角表示的是三维空间中的角度
Irradiance
- 表面上一点在单位面积上吸收的能量,符号E,这里的能量也是Radiant flux
- E=dΦdAE = \frac{dΦ}{dA}E=dAdΦ
Radiance
- 表面上一点p,p在单位立体角、单位面积上发出的能量,符号L,这里的能量还是Radiant flux
L(p,ω)=d2Φ(p,ω)dωdAcosθL(p,ω) = \frac{d^2Φ(p,ω)}{dωdAcosθ}L(p,ω)=dωdAcosθd2Φ(p,ω) - 这个式子的意思是:在一个表面p点处,沿ω方向上发出的能量等于flux除以立体角ω、再除以p点处的有效面积;这个有效面积是指光线垂直表面的部分,所以用面积A乘以光线与表面法线的夹角θ
- 他用来描述某一方向上发射出去的能量
- 他可以用来表示一个拥有Radiant flux为Φ的光源,在单位立体角ω、单位有效面积A上的能量
对比Irradiance与Radiance
- Radiance 比 Irradiance 多了方向性,Radiance 表示 Irradiance 在面积dA的某个方向上吸收到的能量,所以 Irradiance 再除以单位立体角就是 Radiance,即L(p,ω)=dE(p)dωcosθL(p,ω) = \frac{dE(p)}{dωcosθ}L(p,ω)=dωcosθdE(p)
- Irradiance 表示在单位面积dA上吸收的各个方向的能量
- Radiance 则表示在单位面积dA的某一个方向dω上吸收的能量,即Irradiance的微分(由光的可逆性,理解成“吸收”或者“发出”都可以)
- 所以:dE(p,ω)=Li(p,ω)dωcosθdE(p,ω) = L_i(p,ω)dωcosθdE(p,ω)=Li(p,ω)dωcosθ(LiL_iLi表示在ωiω_iωi方向上的Radiance)
- 两边在半球域内对ω积分:E(p)=∫H2Li(p,ω)cosθdωE(p) = \int\limits_{H^2}L_i(p,ω)cosθdωE(p)=H2∫Li(p,ω)cosθdω(这个式子后面会用到)
引入BRDF
当一个光源照射一点p,点p处即会吸收能量也会反射能量,那么到底有多少能量被反射了,为了衡量这个量,从而引入了BRDF(双向反射分布函数 )
当一个光源照射一点p,在某一方向上使p点吸收了一些能量,然后点p又在另一方向反射出了一些能量,衡量这个物体表面对反射的贡献程度就是BRDF的意义
在表面一点p处,沿某一个入射方向ω吸收的能量,可以翻译成Irradiance(E§)的微分,即dE(p,ω),又由上面的内容可得dE(p,ω)=Li(p,ω)dωcosθdE(p,ω) = L_i(p,ω)dωcosθdE(p,ω)=Li(p,ω)dωcosθ
从某一方向ωiω_iωi吸收能量后,这些能量的部分又在另一个方向ωrω_rωr发射出的能量是Radiance(L(p,ω))的微分,即dLrdL_rdLr,(注意Radiance描述的是从各个方向吸收能量,然后从发射方向发射出的能量;从某一方向吸收能量就是Radiane的微分)
所以BRDF就可以表示成
fr(ωi−>ωr)=dLr(ωr)dEi(ωi)=dLr(ωr)dLi(ωi)cosθidωif_r(ω_i->ω_r) = \frac{dL_r(ω_r)}{dE_i(ω_i)} = \frac{dL_r(ω_r)}{dL_i(ω_i)cosθ_idω_i}fr(ωi−>ωr)=dEi(ωi)dLr(ωr)=dLi(ωi)cosθidωidLr(ωr)简单地说,BRDF描述了表面对光反射地贡献程度
用一个词表达BRDF的意义就是“材质”,说了这么多,BRDF其实就相当于材质
引入反射方程
- 由BRDF可以知道:光线从某一方向打到表面,表面吸收这些能量,然后又在另一方向将吸收的部分能量反射出去
- 在实际情况中,我们更想知道表面在反射方向上总共发出了多少能量,这怎么计算?
- 由上面的BRDF变形后,就很简单,在半球空间中其积分即可
dLr(ωr)=fr(ωi−>ωr)dLi(ωi)cosθidωidL_r(ω_r) = f_r(ω_i->ω_r)dL_i(ω_i)cosθ_idω_idLr(ωr)=fr(ωi−>ωr)dLi(ωi)cosθidωi
Lr(p,ωr)=∫H2fr(p,ωi−>ωr)Li(p,ωi)cosθidωiL_r(p,ω_r) = \int_{H^2}f_r(p,ω_i->ω_r)L_i(p,ω_i)cosθ_idω_iLr(p,ωr)=∫H2fr(p,ωi−>ωr)Li(p,ωi)cosθidωi - 上式就是反射方程(The Reflectance Equation),由他可知:表面吸收周围的能量后,通过BRDF损失掉一部分,最后得到在反射方向上发出的能量
- 自此,打开PBR大门的钥匙就有了,因为PBR遵循的是物理原理,而反射方程是根据物理原理总结出来的
实现BRDF
- 实现PBR首先要实现BRDF,现在已经有很好几种BRDF模型,但几乎所有实时渲染管线使用的都是Cook-Torrance BRDF模型
- Cook-Torrance BRDF兼有漫反射和镜面反射两个部分:
fr=kdflambert+ksfcook−torrancef_r = k_df_{lambert} + k_sf_{cook-torrance}fr=kdflambert+ksfcook−torrance - flambertf_{lambert}flambert漫反射部分(当一束光线碰到物体表面时,它会被分离成折射部分和反射部分,折射部分也就是漫反射,反射部分就是我们所说的镜面)
- kdk_dkd入射光线中被漫反射部分的能量所占的比率
- fcook−torrancef_{cook-torrance}fcook−torrance镜面反射部分
- ksk_sks被镜面反射部分的比率
漫反射部分
- flambertf_{lambert}flambert表示的是漫反射部分,被称为Lambertian漫反射
flambert=cπf_{lambert} = \frac{c}{π}flambert=πc - c表示表面颜色
- 除以π是为了对漫反射光进行标准化,因为前面含有BRDF的积分方程是受π影响的
镜面反射部分
fcook−torrance=DFG4(ωo⋅n)(ωi⋅n)f_{cook-torrance} = \frac{DFG}{4(ω_o⋅n)(ω_i⋅n)}fcook−torrance=4(ωo⋅n)(ωi⋅n)DFG
- 字母D,F与G分别代表着一种类型的函数,各个函数分别用来近似的计算出表面反射特性的一个特定部分
- 每一种函数都是用来估算相应的物理参数的,而且用来实现相应物理机制的每种函数都有不止一种形式,下面使用Epic Games公司在UE4中所使用的函数
正态分布函数(Normal Distribution Function)
- 首先要再次引入一个新的概念,微平面模型
- 所有的PBR技术都基于微平面理论。这项理论认为,达到微观尺度之后任何平面都可以用被称为微平面的细小镜面来进行描绘。根据平面粗糙程度的不同,这些细小镜面的法向可以相当不一致:
- 正态分布函数就是为了估算:在受到表面粗糙度的影响下,微平面法向与半程向量一致的数量
- 正态分布函数是从统计学上近似的表示了与半程向量h方向一致的微平面的比率
- 使用Trowbridge-Reitz GGX现实:
NDFGGXTR(n,h,α)=α2π((n⋅h)2(α2−1)+1)2NDF_{GGXTR}(n,h,α) = \frac{α^2}{π((n⋅h)^2(α^2-1)+1)^2}NDFGGXTR(n,h,α)=π((n⋅h)2(α2−1)+1)2α2 - α表示表面粗糙度
- h表示用来与平面上微平面做比较用的半程向量
- 当粗糙度很低(也就是说表面很光滑)的时候,与半程向量方向一致的微平面会高度集中在一个很小的半径范围内。由于这种集中性,NDF最终会生成一个非常明亮的斑点
float D_GGX_TR(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;
}
菲涅尔方程(Fresnel Rquation)
- 描述的是被反射的光线对比光线被折射的部分所占的比率,这个比率会随着我们观察的角度不同而不同
- 当光线碰撞到一个表面的时候,菲涅尔方程会根据观察角度告诉我们被反射的光线所占的百分比。利用这个反射比率和能量守恒原则,我们可以直接得出光线被折射的部分以及光线剩余的能量
- 菲涅尔方程是一个相当复杂的方程式,不过可以用Fresnel-Schlick近似法求得近似解:
FSchlick(h,v,F0)=F0+(1−F0)(1−(h⋅v))5F_{Schlick}(h,v,F_0) = F_0 + (1 - F_0)(1 - (h⋅v))^5FSchlick(h,v,F0)=F0+(1−F0)(1−(h⋅v))5 - F0F_0F0表示平面的基础反射率
- 电介质材质表面的基础反射率都不会高于0.17,金属材质表面的基础反射率起点更高一些并且(大多)在0.5和1.0之间变化
- 对于导体或者金属表面而言基础反射率一般是带有色彩的(这种现象只能在金属表面观察到),这也是为什么F0F_0F0要用RGB三原色来表示的原因
- 金属工作流的概念——由金属表面这些和电介质表面相比所独有的特性引出,也就是我们需要额外使用一个被称为金属度(Metalness)的参数来参与编写表面材质。金属度用来描述一个材质表面是金属还是非金属的。
vec3 F0 = vec3(0.04);
F0 = mix(F0, surfaceColor.rgb, metalness);//如果是金属表面的话就需要对基础反射率添加色彩
- 对于菲涅尔函数总结两点:
- 我们为大多数电介质表面定义了一个近似的基础反射率。F0取最常见的电解质表面的平均值,这又是一个近似值。不过对于大多数电介质表面而言使用0.04作为基础反射率已经足够好了,而且可以在不需要输入额外表面参数的情况下得到物理可信的结果
- 基于金属表面特性,我们要么使用电介质的基础反射率要么就使用F0F_0F0来作为表面颜色。因为金属表面会吸收所有折射光线而没有漫反射,所以我们可以直接使用表面颜色纹理来作为它们的基础反射率
vec3 fresnelSchlick(float cosTheta, vec3 F0)
{
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);//cosTheta是表面法向量n与观察方向v的点乘的结果。
}
几何函数(Geometry Function)
- 描述了微平面自成阴影的属性
- 当一个平面相对比较粗糙的时候,平面表面上的微平面有可能挡住其他的微平面从而减少表面所反射的光线
- 从统计学上近似的求得了微平面间相互遮蔽的比率,这种相互遮蔽会损耗光线的能量
- 与NDF类似,几何函数采用一个材料的粗糙度参数作为输入参数,粗糙度较高的表面其微平面间相互遮蔽的概率就越高
- 使用的几何函数是GGX与Schlick-Beckmann近似的结合体,因此又称为Schlick-GGX:
GSchlickGGX(n,v,k)=n⋅v(n⋅v)(1−k)+kG_{SchlickGGX}(n,v,k) = \frac{n⋅v}{(n⋅v)(1-k)+k}GSchlickGGX(n,v,k)=(n⋅v)(1−k)+kn⋅v - k是α基于直接光照或者IBL光照的重映射(Remapping) :
kdirect=(α+1)28k_{direct} = \frac{(α+1)^2}{8}kdirect=8(α+1)2
kIBL=α22k_{IBL} = \frac{α^2}{2}kIBL=2α2 - IBL,Image based lighting,基于图像的光照(之后会有专题报道。。。)
- 为了有效的估算几何部分,需要将观察方向(几何遮蔽(Geometry Obstruction))和光线方向向量(几何阴影(Geometry Shadowing))都考虑进去。我们可以使用史密斯法(Smith’s method)来把两者都纳入其中:
G(n,v,l,k)=GSchlickGGX(n,v,k)GSchlickGGX(n,l,k)G(n,v,l,k) = G_{SchlickGGX}(n,v,k)G_{SchlickGGX}(n,l,k)G(n,v,l,k)=GSchlickGGX(n,v,k)GSchlickGGX(n,l,k)
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;
}
Cook-Torrance反射方程
- 将上面的内容总结一下,得到Cook-Torrance反射方程:
Lo(p,ωo)=∫Ω(kdcπ+ksDFG4(ωo⋅n)(ωi⋅n))Li(p,ωi)n⋅ωidωiL_o(p,ω_o) = \int\limits_Ω(k_d\frac{c}{π} + k_s\frac{DFG}{4(ω_o⋅n)(ω_i⋅n)})L_i(p,ω_i)n⋅ω_idω_iLo(p,ωo)=Ω∫(kdπc+ks4(ωo⋅n)(ωi⋅n)DFG)Li(p,ωi)n⋅ωidωi - n⋅ωin⋅ω_in⋅ωi是cosθicosθ_icosθi,入射光线的方向 ωiω_iωi与表面法相n的点乘
- BRDF的实现即可得到解决???并不是
参数的输入
- 在Cook-Torrance BRDF模型中提到了表面颜色、法线、粗糙度、反射率、金属度等一些参数,这些参数都会提前被制作成相应的纹理,以至于我们可以逐片段的控制物体表面每个点的属性
各种纹理
- 反射率(Albedo)纹理:指定表面颜色或者反射率。他与漫反射纹理类似,不同的是漫反射纹理中常常包含一些细小的阴影或者深色的裂纹;而反射率纹理中是不会有这些东西的,只包含表面的颜色
- AO纹理:环境光遮蔽纹理,为表面和周围潜在的几何图形指定了一个额外的阴影因子。弥补反射率纹理的不足
- 金属度(Metallic)纹理:逐纹素的指定物体是不是金属质地
- 粗糙度(Roughness)纹理:逐纹素指定表面粗糙度。粗糙的表面会得到更宽阔更模糊的镜面反射,而一个比较光滑的表面则会得到集中而清晰的镜面反射
kd、ksk_d、k_skd、ks
- 菲涅尔方程的返回值F可以直接当作ksk_sks, 因为他们都是表示的意义一样,镜面反射在所有打在物体表面上的光线的贡献程度
- 有了ksk_sks就可以很容易计算折射的比值kdk_dkd,因为我们假设光线打到物体表面后除了反射就是折射,忽略能量损失
vec3 kS = F;
vec3 kD = vec3(1.0) - kS;
kD *= 1.0 - metallic;//这一步是因为只有非金属材质才有漫反射部分,metallic从金属度纹理中采样得到
PBR中BRDF的实现相关推荐
- PBR中BRDF常用的各类法线分布函数、几何函数总结(unity)
PBR中BRDF常用的各类法线分布函数.几何函数总结 一,法线分布函数(Normal Distribution Function,NDF) 1.1 各项同性NDF总结 1.1.1Blinn-Phong ...
- PBR中引入IBL——镜面反射篇
文章目录 PBR中引入IBL--镜面反射篇 回顾上一篇:漫反射 镜面反射的计算思路 镜面反射部分方程的分解 生成预计算纹理 必要的预备知识 镜面波瓣 蒙特卡洛积分(Monte Carlo Integr ...
- 【笔记】PBR,BRDF总结
bsdf = brdf + btdf brdf:用于描述光(辐射能量)在两个物体交界处怎么反射.怎么折射 这个定律的前提是两个表面是光学光滑的,而现实世界中基本不存在这样的表面,所以又搞出来个微表面理 ...
- 【TA-霜狼_may-《百人计划》】图形5.1 PBR基础 BRDF介绍
[TA-霜狼_may-<百人计划>]图形5.1 PBR基础 BRDF介绍 @[TOC]([TA-霜狼_may-<百人计划>]图形5.1 PBR基础 BRDF介绍 5.1.1 P ...
- PBR中引入IBL——漫反射篇
文章目录 PBR中引入IBL--漫反射篇 IBL 分解渲染方程 irradiance map的生成和作用 irradiance map生成过程 环境纹理envTexture的格式 环境纹理envTex ...
- 关于pbr中镜面IBL低差异序列中的 Van Der Corput 序列
源代码是这样的,乍一看的很难的,但其实仔细去解剖还是很好理解的 float RadicalInverse_VdC(uint bits) {bits = (bits << 16u) | (b ...
- 【PBR系列三】BRDF方程及渲染方程
本文核心知识主要参照<现代计算机图形学入门-闫令琪课程课件PPT>,后续光线追踪系列知识也源于此处. 一.BRDF方程 通过上一部分所有辐射度量学各种概念的定义之后,我们可以从这样一个角度 ...
- 探究PBR的两种流程以及Unity中的PBS
原文链接 前言 通过上一篇博客PBR原理我们大概了解了PBR的一些基础理念,这篇博客就让我们来探究一下PBR的两种流程和Unity中两种PBS材质,毕竟Unity是我主要学习的引擎(希望未来有机会接触 ...
- UE4中的PBR材质
PBR材质系统原理简介 一.自然界材质 要学会使用PBR首先需要了解什么是PBR,需要从真实世界的这些PBR材质特有的属性拆分开来去了解他们,这样我们就需要了解光,物体表面材质以及光是如何与材质交互的 ...
最新文章
- python批量下载网页文件-python使用selenium实现批量文件下载
- 【Java报错】记录一次 sun.misc.Unsafe.park(Native Method) Conflicting setter definitions for property 导致的内存泄露
- mysql做主从复制配置案例
- .NET 6 Preview 6 Released
- 设置电脑右下角显示自己的大名
- 今天的几个财务词汇--待查
- 剑指offer 面试63题
- 选用计算机教材的理由原因,教材选用及管理规定
- esp8266 python 74hc595_十九 ,ESP32 74HC595 的使用
- UFS系列九:UFS数据安全
- NewPanderKing 抬头是山,路在脚下! vs2010 问题 LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏
- 130 个相见恨晚的超实用网站
- 闲鱼的排名规则是什么,闲鱼排名规则方法?
- Proximal和ADMM
- 20 - Slider组件案例 相亲APP
- 大数据背景下的信息资源管理
- 520 钻石争霸赛 2021 7-8 浪漫侧影 (25 分)
- fedora 下常用软件安装
- @支付宝@微信支付,世界第一要来和你们抢生意了!
- 看张亚飞《.Net for Flash FMS》的笔记
热门文章
- 安装composer报错Project directory fecshop/ is not empt
- 2023蓝桥杯学习与刷题建议
- struts2文件上传类型限制 之 zip和rar文件类型
- U盘启动快捷键查询列表
- DVB digital vedio broadcasting
- ubuntu linux0.12,ubuntu Linux 安装 jdk1.6.0_12和 Netbean 6.5
- 解码元宇宙,深度剖析元宇宙空间+数字人+数字孪生
- CSDN待审核文章测试
- Java写的滑雪爱好者组织活动,预约活动,参与竞赛系统源码
- 嵌入式和Python的区别是什么?