ShaderToy 实 验 记 - Cook-Torrance

这篇推文是"Advanced Global Illumination 2nd"这本书第二章其中一部分的笔记,这本书非常好,但第二章有些地方没有讲细(可能是大佬的常识),作为内容的补充,这篇文章主要整理介绍Cook-Torrance BRDF包含的三个函数,并在最后,在ShaderToy里完成一个基于Cook-Torrance的光照模型。

image

双向反射分布函数

我们看到一个表面,实际上是周围环境的光照射到表面上,然后表面将一部分光反射到我们眼睛里。双向反射分布函数BRDF-Bidirectional Reflectance Distribution Function就是描述表面入射光和反射光关系的。

x处的BRDF定义为在出射方向\Theta上反射的相对辐射亮度dL与通过不同立体角d \omega_{\Psi}入射的相对辐照度dE之比。BRDF表示为f_{r}(x, \Psi \rightarrow \Theta)

\begin{aligned}f_{r}(x, \Psi \rightarrow \Theta) &=\frac{d L(x \rightarrow \Theta)}{d E(x\leftarrow \Psi)} \\&=\frac{d L(x \rightarrow \Theta)}{L(x\leftarrow\Psi) \cos \left(N_{x}, \Psi\right) d \omega_{\Psi}}\end{aligned}

其中\Psi是入射光方向,\Theta是观察方向,也就是反射光方向。

由此可以得出入射与反射亮度之间的关系。
L(x \rightarrow \Theta)=\int_{\Omega x}f_{r}(x, \Psi \rightarrow \Theta) L(x \leftarrow \Psi)\cos \left(N_{x}, \Psi\right) d \omega_{\Psi}

接下来就是分析Cook-Torrance的着色模型。

BRDF性质

非负性
f_{r}(x, \Psi \rightarrow \Theta)\geq0
亥姆霍兹互反律
f_{r}(x, \Psi \leftrightarrow \Theta)
能量守恒
\forall\Psi,\int_{\Omega x}{f_{r}(x, \Psi \rightarrow \Theta)}\cos (N_x,\Theta) d w_{\Theta} \leq 1

微平面理论

大多数真实世界的表面不是光学上光滑的,但是具有比光波长大得多但比像素小的尺度的不规则性。 这种微观几何(microgeometry)变化导致每个表面点反射(和折射)不同方向的光:材质的部分外观组成是这些反射和折射方向的聚合结果。

image

在微观尺度上,表面越粗糙,反射越模糊,因为表面取向与整个宏观表面取向的偏离更强。

image

Cook-Torrance 着色模型

Cook-Torrance着色模型就是基于微平面理论的一种着色模型。
f_{r}(x, \Psi \leftrightarrow \Theta)=\frac{F(\beta)}{\pi} \frac{D\left(\theta_{h}\right) G}{(N \cdot \Psi)(N \cdot \Theta)}+k_{d}

Cook-Torrance BRDF的镜面反射部分包含三个函数,此外分母部分还有一个标准化因子 。字母D/F/G分别代表着一种类型的函数,各个函数分别用来近似的计算出表面反射特性的一个特定部分。三个函数分别为法线分布函数(Normal Distribution Function),菲涅尔方程(Fresnel Rquation)和几何函数(Geometry Function)。

法线分布函数:估算在受到表面粗糙度的影响下,取向方向与中间向量一致的微平面的数量。这是用来估算微平面的主要函数。

几何函数:描述了微平面自成阴影的属性。当一个平面相对比较粗糙的时候,平面表面上的微平面有可能挡住其他的微平面从而减少表面所反射的光线。

菲涅尔方程:菲涅尔方程描述的是在不同的表面角下表面所反射的光线所占的比率。

以上的每一种函数都是用来估算相应的物理参数的,而且你会发现用来实现相应物理机制的每种函数都有不止一种形式。它们有的非常真实,有的则性能高效。你可以按照自己的需求任意选择自己想要的函数的实现方法。

Fresnel因子

电磁波碰到物体表面时,会产生反射波透射波反射波的能量等于入射电磁波的能量减去透射电磁波的能量。值得一提的是,菲涅尔反射的方程可以通过麦克斯韦电磁学方程组推导出来,因为本质上讲菲涅尔反射其实是使用的波动理论来解释光的反射现象。

光又是一种电磁波,当光线碰撞到一个表面的时候,菲涅尔方程会根据观察角度告诉我们被反射的光线所占的百分比。利用这个反射比率和能量守恒原则,我们可以直接得出光线被折射的部分以及光线剩余的能量

image

当垂直观察的时候,任何物体或者材质表面都有一个基础反射率,但是如果以一定的角度往平面上看的时候所有反光都会变得明显起来。比如这张图,河流近处的能看见河底,河流远处却是反射的天空与环境。这种现象因菲涅尔而闻名,并体现在了菲涅尔方程之中。

image

入射光的电场可以分解为相对某一平面的极化分量,通常选择包含表面法向量\mathbf{N}和指向光源的方向\mathbf{L}的平面为极化平面,与该平面平行的分量称为p极化分量,垂直的分量称为s极化分量。

image

对于s偏振

\begin{aligned}E+E^{\prime}=&E^{\prime\prime}\\H\cos\theta-H^{\prime}\cos\theta^{\prime}=&H^{\prime\prime}\cos\theta^{\prime\prime}\end{aligned}

利用H=\sqrt{\frac{\varepsilon}{\mu}}E,并取\mu=\mu_0可得

\begin{aligned}\sqrt{\varepsilon_{1}}\left(E-E^{\prime}\right)\cos\theta=&\sqrt{\varepsilon_{2}}E^{\prime\prime}\cos\theta^{\prime\prime}\\\frac{\sin\theta}{\sin\theta^{\prime\prime}}=&\sqrt{\frac{\varepsilon_{2}}{\varepsilon_{1}}}\\\frac{E^{\prime}}{E}=\frac{\sqrt{\varepsilon_{1}}\cos\theta-\sqrt{\varepsilon_{2}}\cos\theta^{\prime\prime}}{\sqrt{\varepsilon_{1}}\cos\theta+\sqrt{\varepsilon_{2}}\cos\theta^{\prime \prime}}=&-\frac{\sin\left(\theta-\theta^{\prime\prime}\right)}{\sin\left(\theta+\theta^{\prime\prime}\right)}\\\frac{E^{\prime \prime}}{E}=\frac{2\sqrt{\varepsilon_{1}}\cos\theta}{\sqrt{\varepsilon_{1}}\cos\theta+\sqrt{\varepsilon_{2}}\cos\theta^{\prime \prime}}=&\frac{2\cos\theta\sin\theta^{\prime\prime}}{\sin\left(\theta+\theta^{\prime\prime}\right)}\end{aligned}

对于p偏振
\begin{aligned}H+H^{\prime}=&H^{\prime\prime} \\E\cos\theta-E^{\prime}\cos\theta^{\prime}=&E^{\prime\prime}\cos\theta^{\prime \prime}\end{aligned}

利用H=\sqrt{\frac{\varepsilon}{\mu}} E,并取\mu=\mu_0可得

\begin{aligned} \sqrt{\varepsilon_{1}}\left(E+E^{\prime}\right)=&\sqrt{\varepsilon_{2}} E^{\prime \prime}\\ \frac{\sin \theta}{\sin \theta^{\prime \prime}}=&\sqrt{\frac{\varepsilon_{2}}{\varepsilon_{1}}}\\ \frac{E^{\prime}}{E}=&\frac{\tan \left(\theta-\theta^{\prime \prime}\right)}{\tan \left(\theta+\theta^{\prime \prime}\right)}\\ \frac{E^{\prime \prime}}{E}=&\frac{2 \cos \theta \sin \theta^{\prime \prime}}{\sin \left(\theta+\theta^{\prime \prime}\right) \cos \left(\theta-\theta^{\prime \prime}\right)} \end{aligned}

入射光线与折射光线的方向由斯涅尔定律约束
\eta_{1}\sin \theta_{1}=\eta_{2}\sin \theta_{2}
对某一波长,Fresnel因子给出这两个极化分量的反射数值的表达式如下:
\begin{aligned}F_{s}=&\left(\frac{\sin \left(\theta_{1}-\theta_{2}\right)}{\sin\left(\theta_{1}+\theta_{2}\right)}\right)^{2}=\left(\frac{\eta_{1} \cos \theta_{i}-\eta_{2} \cos \theta_{t}}{\eta_{1} \cos \theta_{i}+\eta_{2} \cos \theta_{t}}\right)^{2}\\F_{p}=&\left(\frac{\tan ^{2}\left(\theta_{1}-\theta_{2}\right)}{\tan ^{2}\left(\theta_{1}+\theta_{2}\right)}\right)^{2}=\left(\frac{\eta_{1} \cos \theta_{t}-\eta_{2} \cos \theta_{i}}{\eta_{1} \cos \theta_{t}+\eta_{2} \cos \theta_{i}}\right)^{2}\end{aligned}
其中,\theta_{1}为入射角,\theta_{2}为与波长相关的透射角。图形学中通常考虑光是非偏振光。对于非偏振光,可用以上极化分量的平均值作为波长为\lambda的电磁波的Fresnel因子F_{\lambda}
F_{\lambda}=\frac{F_{p}+F_{s}}{2}

float fresnel(float cosi, float cost, float etai,
        float etat) {
    float rs = (etat * cosi - etai * cost) 
    / (etat * cosi + etai * cost);
    float rp = (etai * cosi - etat * cost) 
    / (etai * cosi + etat * cost);
    return (rs * rs + rp * rp) * 0.5f;
}

Fresnel-Schlick近似法

鉴于导体的菲涅耳方程较复杂,Schlick提供了一个近似的函数:
F_{\text {Schlick}}\left(\mathbf{H}, \mathbf{V}, F_{0}\right)=F_{0}+\left(1-F_{0}\right)(1-(\mathbf{H} \cdot \mathbf{V}))^{5}

F_{0}表示平面的基础反射率,它是利用所谓折射指数(Indices of Refraction)/IOR计算得出的。

Fresnel Schlick近似可以用代码表示为:

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

通用的折射率IOR与F_{0}的关系式如下
F_{0}=\left(\frac{\eta_{1}-\eta_{2}}{\eta_{1}+\eta_{2}}\right)^{2}
其中,\eta_1\eta_2分别为两种介质的折射率。通常假设\eta_1=1近似于空气的折射率,并用\eta替换\eta_2,于是,上式可以简化为:
F_{0}=\left(\frac{\eta-1}{\eta+1}\right)^{2}
这就是我们通常看到的F_{0}和折射率之间的转换公式。

在有些渲染器中,会直接采用折射率IOR来表示材质的属性,以下是一张渲染器中实数折射率、粗糙度二维材质的渲染对照图

[图片上传失败...(image-faedc3-1587550500025)]

材质属性

由于光由电磁波组成,因此,物质的光学特性与其导电特性密切相关。我们通常把导电性较差的材质,如煤、人工晶体、琥珀、陶瓷等称为绝缘体。而把导电性比较好的金属如金、银、铜、铁、锡、铝等称为导体。以及将导电性质介于导体和绝缘体之间的材质称为半导体。

即根据导电特性,可将现实生活中的物质分为三个主要光学类别:

  1. 电介质-Dielectrics,又称绝缘体-Insulators,非金属
  2. 半导体-Semiconductors
  3. 金属-Metals,又称导体-Conductors

附上浅墨大佬的PBR白皮书的常见材质F_{0}参考速查图表
[图片上传失败...(image-ae097a-1587550500025)]

微平面分布函数

法线分布函数,即微平面分布函数,描述了平面法线分布的概率,即具有正确朝向的微表面法线浓度。微平面的法线分布函数D_{m}描述了微观表面上的表面法线m的统计分布。

可以将法线分布函数D_{m}理解为微观几何表面区域上的微平面表面法线的统计分布。对D_{m}在整个微平面法线上积分,会得到微表面的面积

一般我们用宏观表面的半矢量\mathbf{H}来表示微观表面法线\mathbf{m},因为仅\mathbf{m}=\mathbf{H}的表面点的朝向才会将光线\mathbf{L}反射到视线\mathbf{V}的方向,其他朝向的表面点对BRDF没有贡献(正负相互抵消)。

性质

  1. 微平面法线密度始终为非负值:

0 \leqslant D(\mathbf{m}) \leqslant \infty

  1. 微表面的总面积始终不小于宏观表面总面积:

\int_{\mathbf{m} \in \Theta} D(\mathbf{m}) d \mathbf{H} \geqslant 1

  1. 任何方向上微观表面投影面积始终与宏观表面投影面积相同:

\int_{\mathbf{m} \in \Theta} D(\mathbf{m})(\mathbf{V} \cdot \mathbf{H}) d \mathbf{H}=\mathbf{V} \cdot \mathbf{N}

  1. 若观察方向为法线方向,则其积分可以归一化。即\mathbf{V} = \mathbf{N}时,有:

\int_{\mathbf{m} \in \Theta} D(\mathbf{m})(\mathbf{N} \cdot \mathbf{H}) d \mathbf{H}=1

Beckmann分布

Beckmann分布是光学业界开发的第一批微平面模型中使用的法线分布。也是Cook-Torrance BRDF在提出时选择的NDF。

给定中间向量\mathbf{H},微平面分布函数返回法向量与中间向量\mathbf{H}相同的微平面的比例。对于粗糙平面,即各向同性表面的微平面分布函数D_{m}(Beckmann分布函数)为
D_{B}(\mathbf{m})=\frac{1}{\pi m^{2}(\mathbf{N} \cdot \mathbf{H})^{4}} \exp \left(\frac{(\mathbf{N} \cdot \mathbf{H})^{2}-1}{m^{2}(\mathbf{N} \cdot \mathbf{H})^{2}}\right)

其中,m微平面斜率的均方根,表示了微平面法向量的分布情况。

m的值越大,对应的平面越粗糙,微平面的法向量分布越广。m的值越小,表面越光滑,微平面法向量分布范围越窄,可以产生锐利的高光效果。

UE4中对Beckmann分布的实现代码如下

float D_Beckmann( float a2, float NoH )
{
    float NoH2 = NoH * NoH;
    return exp( (NoH2 - 1) / (a2 * NoH2) ) /
            ( PI * a2 * NoH2 * NoH2 );
}

GGX分布

GGX,即Trowbridge-Reitz分布,最初由Trowbridge和Reitz推导出,在Blinn 1977年的论文中也有推荐此分布函数,但一直没有受到图形学界的太多关注。30多年后,Trowbridge-Reitz分布被Walter等人独立重新发现,并将其命名为GGX分布。

在重新发现并提出GGX分布之后,GGX分布采用风潮开始在电影和游戏行业中广泛传播,成为了如今游戏行业和电影行业中最常用的法线分布函数。

D_{G G X}(\mathbf{m})=\frac{\alpha^{2}}{\pi\left((\mathbf{N} \cdot \mathbf{H})^{2}\left(\alpha^{2}-1\right)+1\right)^{2}}

在流行的模型中,GGX拥有最长的尾部。这是GGX能够日益普及的主要原因。

image

使用GLSL代码编写的Trowbridge-Reitz GGX如下

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

各向异性

以上函数是各向同性的,也就是绕法向量\mathbf{N}旋转时函数值不变,当观察方向\mathbf{V}和指向光源的方向\mathbf{L}不变,并且它们与法向量之间的夹角不变时,微平面的分布也保持不变。

然而,很多表面在不同方向上的粗糙度不同,这些表面被称为各向异性的反射面,包括雾面金属、毛发和织物等材料表面都属于这类反射面。

image

有些表面有多重粗糙度,这种情况下,可用不同粗糙度微平面分布函数的加权平均来表示该表面的微平面分布函数,如下式所示。
D(\mathbf{V}, \mathbf{L})=\sum_{i=1}^{n} w_{i} D_{m_{i}}(\mathbf{V}, \mathbf{L})

Anisotropic Beckmann Distribution

对于各向异性的表面,Beckmann微平面分布函数为
D_{B a n i s o}(\mathbf{m})=\frac{1}{4 m_{x} m_{y}(\mathbf{N} \cdot \mathbf{H})^{4}} \exp \left[\left(\frac{(\mathbf{T} \cdot \mathbf{P})^{2}}{m_{x}^{2}}+\frac{1-(\mathbf{T} \cdot \mathbf{P})^{2}}{m_{y}^{2}}\right) \frac{(\mathbf{N} \cdot \mathbf{H})^{2}-1}{(\mathbf{N} \cdot \mathbf{H})^{2}}\right]
其中,m是一个二维粗糙度向量,m_{x}m_{y}分别表示与切线方向\mathbf{T}平行和垂直的斜率均方根,向量\mathbf{P}是中间向量\mathbf{H}到切平面的规范化投影。
\mathbf{P}=\frac{\mathbf{H}-(\mathbf{N} \cdot \mathbf{H}) \mathbf{N}}{\|\mathbf{H}-(\mathbf{N} \cdot \mathbf{H}) \mathbf{N}\|}

以下为UE4中Anisotropic Beckmann分布的Shader实现代码:

// Anisotropic Beckmann
float D_Beckmann_aniso( float ax, float ay, float NoH,
         float3 H, float3 X, float3 Y )
{
    float XoH = dot( X, H );
    float YoH = dot( Y, H );
    float d = - (XoH*XoH / (ax*ax) + YoH*YoH /(ay*ay)) 
            / NoH*NoH;
    return exp(d) / 
            ( PI * ax*ay * NoH * NoH * NoH * NoH );
}

Anisotropic GGX Distribution

各项异性的GGX分布形式如下
D_{G G X a n i s o}(\mathbf{m})=\frac{1}{\pi m_{x} m_{y}} \frac{1}{\left(\frac{(\mathbf{T} \cdot \mathbf{H})^{2}}{m_{x}^{2}}+\frac{(\mathbf{P} \cdot \mathbf{H})^{2}}{m_{y}^{2}}+(\mathbf{N} \cdot \mathbf{H})^{2}\right)^{2}}

以下为UE4中Anisotropic Beckmann分布的Shader实现代码:

// Anisotropic Beckmann
float D_Beckmann_aniso( float ax, float ay, float NoH,
        float3 H, float3 X, float3 Y )
{
    float XoH = dot( X, H );
    float YoH = dot( Y, H );
    float d = - (XoH*XoH / (ax*ax) + YoH*YoH / (ay*ay)) 
            / NoH*NoH;
    return exp(d) /
            ( PI * ax*ay * NoH * NoH * NoH * NoH );
}

几何衰减因子

在PBR中,几何衰减因子是一个0到1之间的标量,描述了微平面自阴影的属性。照向一个微平面的光线可能被相邻的微平面阻断,而照不到该微平面。微平面的反射光线也可能被相邻微平面阻断而反射不出来。

这会导致镜面反射的高光中出现轻微的暗纹,与表面的几何衰减系数相关。被阻断的光线基本沿任意方向散射出去,最后形成表面的漫反射。

几何衰减因子与法线分布函数作为Microfacet Specular BRDF中的重要两项,两者之间具有紧密的联系

  1. 几何衰减因子的解析形式的确认依赖于法线分布函数。
  2. 法线分布函数需要结合几何衰减因子,得到有效的法线分布强度。

V-cavity

通过假设微平面总形成V型槽结构,可以导出表面粗糙度阻断光线的大约数量。通过简单的三角学知识,可以推导出某一微平面的反射光线被相邻微平面阻断后,反射到观察者的光能表达式。设微平面的宽度w,其中观察者可见部分x到达观察者的光线G,通过上图计算,简单推导如下。

image

\begin{aligned}w&=\frac{1}{\sin \alpha}\\x&=\frac{2\sin \gamma}{\sin(\beta+\pi/2)}\\\sin \alpha&=\cos (\pi / 2-\alpha)=\mathbf{N} \cdot \mathbf{H} \\ \sin (\beta+\pi / 2)&=\cos \beta=\mathbf{V} \cdot \mathbf{H} \\ \sin \gamma&=\cos (\pi / 2-\gamma)=\mathbf{N} \cdot \mathbf{V}\\G&=\frac{x}{w}\end{aligned}
经过上面计算,得出几何衰减因子的公式为
\begin{aligned}G(\mathbf{V}, \mathbf{L})&=\min\{ 1,G_{1},G_{2}\} \\&=\min \left\{1, \frac{2(\mathbf{N} \cdot \mathbf{H})(\mathbf{N} \cdot \mathbf{V})}{\mathbf{L} \cdot \mathbf{H}}, \frac{2(\mathbf{N} \cdot \mathbf{H})(\mathbf{N} \cdot \mathbf{L})}{\mathbf{L} \cdot \mathbf{H}}\right\}\end{aligned}
表示微平面的入射光和反射光中被相邻微平面阻断的部分。

Schlick-GGX

我们将要使用的几何函数是GGX与Schlick-Beckmann近似的结合体,这是UE4在SIGGRAPH 2013上公布的方案为基于Schlick近似。

这里的k\alpha基于几何函数是针对直接光照还是针对IBL光照的重映射(采用了Disney对粗糙度的重映射) 。从而使几何项的粗糙度变化更加平滑,更便于美术人员的使用。

\begin{aligned}k=&\frac{\alpha}{2} \\\alpha=&\left(\frac{\text {roughness}+1}{2}\right)^{2} \\G_{1}(\mathbf{V})=&\frac{(\mathbf{N} \cdot \mathbf{V})}{(\mathbf{N} \cdot \mathbf{V})(1-k)+k}\end{aligned}

为了有效的估算几何部分,需要将观察方向(几何遮蔽-Geometry Obstruction)和光线方向向量(几何阴影-Geometry Shadowing)都考虑进去。可以使用Smith’s method来把两者都纳入其中,即:

G(\mathbf{L}, \mathbf{V}, \mathbf{H})=G_{1}(\mathbf{L}) G_{1}(\mathbf{V})

使用Smith’s method与Schlick-GGX作为G_{1}可以得到如下所示不同粗糙度的视觉效果

image

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

性质

标量性

几何衰减因子是0和1之间的一个标量
0 \leq G(\mathbf{L}, \mathbf{V}, \mathbf{H}) \leq 1

低粗糙度下几何函数大多情况下数值接近1

[图片上传失败...(image-5b0a26-1587550500025)]

对称性

几何函数在两个可见方向,即出射和入射上是对称的:
G(\mathbf{L}, \mathbf{V}, \mathbf{H})=G(\mathbf{V}, \mathbf{L}, \mathbf{H})

同向可见性

几何函数从宏观表面正面方向上无法看到微表面的背面,反之亦然:
\begin{aligned} G(\mathbf{L}, \mathbf{V}, \mathbf{H})=0 &\text { if }(\mathbf{L} \cdot \mathbf{H})(\mathbf{L} \cdot \mathbf{N}) \leq 0\\ &\text { or }(\mathbf{V} \cdot \mathbf{H})(\mathbf{V} \cdot \mathbf{N}) \leq 0 \end{aligned}

拉伸不变性

微表面几何轮廓具有拉伸不变性。拉伸微表面轮廓就像拉伸一张图片,即在一个维度上乘以常数因子,不会更改微表面轮廓的拓扑结构:拉伸后,遮挡的光线仍会被遮挡,未遮挡的光线仍未被遮挡。

当微表面轮廓中涉及的所有斜率同时缩放时,遮蔽概率对于配置拉伸是不变的。这包括微表面的斜率和与出射方向相关的斜率。它们都是通过拉伸因子的倒数来缩放的。因此,斜率宽度的分布也被反向拉伸因子拉伸。如下图。

[图片上传失败...(image-16a359-1587550500025)]

Cook-Torrance 渲染方程

随着Cook-Torrance BRDF中所有元素都介绍完毕,我们现在可以将前文中的基于物理的BRDF着色模型纳入到最终的渲染方程里。
f_{r}(x, \Psi \leftrightarrow \Theta)=\frac{F(\beta)}{\pi} \frac{D\left(\theta_{h}\right) G}{(N \cdot \Psi)(N \cdot \Theta)}+k_{d}
带入第二种弗雷德霍姆方程的渲染方程中。根据能量守恒,在某个点和特定初涉方向上的总出射辐射亮度是发射的辐射亮度L_{e}和在该方向上该表面点处反射的辐射亮度L_{r}的总和。
\begin{aligned}L_{r}(x \rightarrow \Theta)&=\int_{\Omega_{x}} f_{r}(x, \Psi \rightarrow \Theta) L(x \leftarrow \Psi) \cos \left(N_{x}, \Psi\right) d \omega_{\Psi}\\L(x \rightarrow \Theta)&=L_{e}(x \rightarrow \Theta)+L_{r}(x \rightarrow \Theta)\end{aligned}

Cook-Torrance的BRDF方程的GLSL代码

vec3 cooktorrance(vec3 pos,vec3 cameraPos,vec3 lightPos,
     vec3 lightIntensity,float roughness) {
    vec3 N = GetNormal(pos);
    vec3 V = normalize(cameraPos - pos);
    vec3 F0 = vec3(0.04); 
    F0 = mix(F0, albedo, metallic);

    // reflectance equation
    vec3 Lo = vec3(0.0);

    vec3 L = normalize(lightPos- pos);
    vec3 H = normalize(V + L);
    float distance2   = length(lightPos- pos);
    float attenuation = 1.0 / (distance2 * distance2);
    vec3 radiance     = lightIntensity * attenuation;        

    // cook-torrance brdf
    float NDF = DistributionGGX(N, H, roughness);        
    float G   = GeometrySmith(N, V, L, roughness);      
    vec3 F    = fresnelSchlick(max(dot(H, V),0.0),F0);       

    vec3 kS = F;
    vec3 kD = vec3(1.0) - kS;
    kD *= 1.0 - metallic;     

    vec3 nominator    = NDF * G * F;
    float denominator = 4.0*max(dot(N, V),0.0)*
         max(dot(N, L), 0.0) + 0.001; 
    vec3 specular     = nominator / denominator;

    // add to outgoing radiance Lo
    float NdotL = max(dot(N, L), 0.0);                
    Lo += (kD*albedo/PI + specular)*radiance*NdotL; 

    return Lo;
}

最后shadertoy里的呈现。


image

参考阅读

https://learnopengl.com/PBR/Theory
http://advances.realtimerendering.com/s2014/epic/TemporalAA.pptx
https://80.lv/articles/the-future-of-real-time-rendering-with-lumberyard/
https://github.com/EpicGames/UnrealEngine
https://github.com/QianMo/PBR-White-Paper/
http://www.cs.utah.edu/~michael/brdfs/jgtbrdf.pdf
http://www.disneyanimation.com/technology/brdf.html

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容