前言

书接前文,让我们来继续实现specular IBL。上回书说到我们可以使用暴力的手段,在片段着色器里实时计算积分来求得最终的光强,只不过采样的时候通过一些数学方法(重要性采样)来提高效率。但是Epic提供了一个更高效的方案,虽然损失了一些精度,但是图形学的本质就是欺骗嘛。

此处列一下后面需要引用到的以前的文章里介绍过的方程。

\[ L_{specular}(p, \vec{v}) = \int_{\vec{l}_i \in \Omega} \color{red}{f_s}\color{black}{} \ast L(p, \vec{l}_i) \ast (\vec{n} \cdot \vec{l}_{i}) \ast d\vec{l}_i \tag{0.1} \]

重要性采样近似方程。

\[ L_{specular}(p, \vec{v}) \approx \frac{1}{N} \sum_{i = 0}^{i \lt N} \frac { f_s \ast L(p, \vec{l_i}) \ast (\vec{n} \cdot \vec{l_i}) } { p_{s}(p, \vec{l_i}, \vec{v}) } \tag{0.14} \]

阅读全文 »

前言

书接上文,让我们继续来实现IBL,上回我们实现了低频域的漫反射间接光,即下面反射率方程的左边部分。

\[ L(p, \vec{v}) = \int_{\vec{l}_i \in \Omega} f_d \ast L(p, \vec{l}_i) \ast (\vec{n} \cdot \vec{l}_{i}) \ast d\vec{l}_i + \int_{\vec{l}_i \in \Omega} f_s \ast L(p, \vec{l}_i) \ast (\vec{n} \cdot \vec{l}_{i}) \ast d\vec{l}_i \tag{0.1} \]

那么本篇则是实现该方程的右边部分。

\[ L_{specular}(p, \vec{v}) = \int_{\vec{l}_i \in \Omega} f_s \ast L(p, \vec{l}_i) \ast (\vec{n} \cdot \vec{l}_{i}) \ast d\vec{l}_i \tag{0.2} \]

这也是一个连续型的积分,所以也需要通过离散化的方程去计算积分,但是这里不能再使用前文提到的黎曼和的方法,因为镜面反射项对精度要求更高,是一个高频域的信号。所以这里采用的是使用重要性采样加速的蒙特卡洛积分, 该方法又称Brute force specular IBL, 很暴力。

下面分别介绍蒙特卡洛积分重要性采样的数学原理,以及我们为了实现specular IBL真正的采样手段所需要的前置数学知识。笔者主观意识里是比较想把这部分拆解清楚的,所以并不会吝啬篇幅(又不是写毕设),所以内容可能有些小长,建议脾气暴躁者先码后看。

阅读全文 »

前言

OpenGL中,每一个三角形面片,都是一个平坦的平面。在该平面上的所有像素点,其法线方向都是相同的。

我们知道,无论是传统的光照模型,还是基于物理的光照模型,法线决定平面的朝向,对于光照的计算至关重要。

所以一个模型的表面法线越接近于真实世界中的法线,获得的光照就越正确,光照细节就越多。

但是目前为止,我们的法线都是跟随顶点数据传到GPU的,并没有精确到像素级的(虽然传到片段着色器时会进行插值,但是同一个表面的法线始终是一样的),这就导致在计算光照的时候我们只能得到平坦的平面,而丢失了平面的凹凸细节。比如,一个砖墙,由许多砖块组成,但是整个砖墙都只有一个法线朝向,完全忽略了砖与砖接缝处的凹凸痕迹。

于是法线贴图就应运而生了。

阅读全文 »

效果

由于这个效果的ps shader有1400多行代码,且复杂度太高,会导致渲染时间比较长,内部为了节约性能做了限制渲染时长的逻辑,即默认如果一个shader等了1秒钟还没绘制好,那就会停止渲染,场景就会不动了。

为了玛丽,这里额外加了一个可供div配置的参数wait_max,以自定义渲染等待时长,所以下面场景的div声明如下所示。

除此之外,还额外加了一个可供div配置的参数time_rate来控制shader里iTime这个uniform值每帧增加多少,该值默认是0.01。

1
2
3
4
5
<div class="shadertoy"
ps="/shaders/shadertoy/supermarry.ps"
wait_max=10.0
time_rate=0.05
> </div>

来源

shadertoy - Mario World

阅读全文 »

效果

该效果用到了贴图,可以在div上添加channel0..4的属性作为贴图的路径,如下例所示。

1
2
3
4
5
<div class="shadertoy"
ps="/shaders/shadertoy/voxel_edges.ps"
channel0="../images/shadertoy/texture/RustyMetal.jpg"
> </div>
<!-- channel0="../images/shadertoy/texture/RGBANoiseMedium.png"-->

来源

shadertoy - Voxel - Edges

阅读全文 »

前言

上篇使用Cook-Torrance BRDF模型实现了精准光源直接光照的计算。本篇继续基于PBR的理论基础,通过对微平面进行半球领域近似积分来计算周围环境作用于物体上的间接光源。

本人能力有限,对其中的某些步骤尚有疑惑之处,希望以后通过进一步的深入学习可以真正地理解每一个过程,共勉。

下面将需要在本篇引用到的理论篇推导过的公式列举一下,方便后面引用。

\[ L(p, \vec{v}) = \int_{\vec{l}_i \in \Omega} f(p, \vec{l}_i, \vec{v}) \ast L(p, \vec{l}_i) \ast (\vec{n} \cdot \vec{l}_{i}) \ast d\vec{l}_i \tag{0.19} \]

\[ f(p, \vec{l}, \vec{v}) = f_{lambert} (p, \vec{l}, \vec{v}) + f_{cook\_torrance} (p, \vec{l}, \vec{v}) \tag{0.21} \]

\[ f_{lambert} (p, \vec{l}, \vec{v}) = k_d \ast \frac {C_{diffuse}} {\pi} \tag{0.22} \]

IBL简介

基于图像的光照(Image Based Lighting)是计算PBR间接光照的一种方法,用于计算除了精准光源之外的其他环境光照。

该方法将物体周围的整体环境作为一个大的光源作用于物体。所以我们需要对物体的每一个平面的半球领域进行积分才能获得最终的光照强度,即对每一个微平面来说,它会接收任意方向上的光源。

我们同样将间接光照分为漫反射项镜面反射项两部分进行计算。

阅读全文 »

前言

上篇介绍了PBR的一些理论基础,本篇基于这些理论,并选择了一个典型的Cook-Torrance BRDF模型,来尝试实现一下精准光源直接光照的计算,其中所引用到的上节的公式先列于此,以便后面引用。

\[ L(p, \vec{v}) = \int_{\vec{l}_i \in \Omega} f(p, \vec{l}_i, \vec{v}) \ast L(p, \vec{l}_i) \ast (\vec{n} \cdot \vec{l}_{i}) \ast d\vec{l}_i \tag{0.19} \]

\[ f_{lambert} (p, \vec{l}, \vec{v}) = k_d \ast \frac {C_{diffuse}} {\pi} \tag{0.22} \]

\[ f_{cook\_torrance}(p, \vec{l}, \vec{v}) = \frac {D(p, \vec{h}) \ast G(p, \vec{l}, \vec{v}) \ast F(p, \vec{l}, \vec{v})} {4 \ast (\vec{n} \cdot \vec{v}) \ast (\vec{n} \cdot \vec{l})} \tag{0.23} \]

阅读全文 »

辐射度量学

辐射度量学是用来研究电磁辐射能量的科学。所以在这里,PBR使用辐射度量学的一些概念作为能量的表述单位,从而使得到的公式在能量方面得到定量的准确度。要想理清PBR的理论,就不得不明白辐射度量学的一些基本概念。

阅读全文 »