GAMES 101 现代计算机图形学基础 笔记(下篇).

  • 光线追踪(Whitted-style,求交算法,加速结构,辐射度量学,路径追踪)
  • 材质与外观
  • 动画与模拟

光线追踪 Ray Tracing

从问题出发

如何用光栅化的手法解决阴影的问题?

重要思想:点不在阴影中,当且仅当点必须同时被光源和摄像机看到。

  1. 从光源看向场景(用 Z-buffer’ 记录深度)
  2. 从摄像机看向场景
  3. 如果两深度相同,则无需阴影;若两深度不同,则在阴影中。

这样做存在的问题:

  • Hard shadows(阴影被 0/1 化,无法表示阴影的程度)

提出光线追踪,就是为了解决光线追踪无法很好地处理全局效果的问题。

  • Soft Shadows
  • Glossy reflection
  • Indirect illumination (光线会弹射不止一次)

光线追踪生成的图片质量很高,但是是离线的算法,运作速度也很慢。

基础算法

相关定义

  • 光线

    • 光线沿直线传播
    • 光线和光线并不会发生碰撞
    • 光线总是从光源发出,终止于人的眼睛(我们需要模拟的就是这个过程)
      • 根据光路的可逆性,我们可以假设“感知光线”从人眼出发…
  • 光线投射

image-20220114154759095

对于我们眼前的成像平面的每一个像素点,从人眼发出一条“感知光线”经过这个像素点,可能会触碰到场景中的某个位置。如果该位置和光源的连线上无其它物体的遮挡,那么我们就可以直接对其进行着色计算。

image-20220114155221509

Whitted-style Ray Tracing

image-20220114155905503

思路:模拟光线不断弹射的过程,并记录光线在每一个弹射点的衰减率。如上图中,对于玻璃球,需要模拟其反射和折射光路。具体的技术实现见下。

光线和物体表面交点的求法

  • 对于隐式表面

光线的定义:原点 $\vec o$​​,传播方向 $\vec d \ (||\vec d||=1)$​​​,光线定义为 $\vec r(t) = \vec o +t\vec d, \ t\ge0$​​。

球的定义:$\vec p: (\vec p - \vec c)^2 - R^2 = 0$.

  • 对于显式表面

一个简单的想法是对模型的所有三角形表面做遍历,然后选择 $t$ 最小的那个。(可能不存在,可以优化*)

于是,接下来我们仅考虑光线如何与单个三角形求交。

定义平面为 $(p-p’) \cdot N = 0$.

然后判断交点是否在三角形内。

此外还有 Möller Trumbore 算法,可以直接判断交点是否在三角形内(需要用到克莱姆法则):

该怎样加速与模型求交呢(*)?

  • Naive algorithm = #pixels ⨉ # traingles (⨉ #bounces) 太慢了,不能满足我们的需求

  • Improved Algorithm: Bounding Volume

    • 这里我们仍然引入“包围盒”的思想,这里称为 Bounding Volume
    • 光线能够与模型有交点的必要条件:光线能够与包围模型的一个简单包围体积有交点

image-20220114163023985

我们将长方体理解成三个对面所分划出的空间的交集。我们一般使用的包围体积便是长方体,且长方体是与坐标轴平行的,即轴对齐包围盒(AABB)。选用 AABB 式包围盒有利于加速计算。判断光线和 AABB 类包围盒的求交方法如下:

image-20220114163501816

核心思想:只有当光线进入所有三个对面后,光线才进入了包围盒;若光线从某一个对面出射,则光线便从包围盒中射出。于是我们可以计算三个对面分别对应的 $t_{min}$​​ 和 $t_{max}$​​,然后对其求交。当且仅当 $t_{enter} \lt t_{exit}$​​ 且 $t_{exit} \ge 0$​​,光线才可能与包围盒有交点。

使用包围盒加速光线追踪

Uniform Grids

① 预处理

image-20220114165308910

一般来说,取格子数 #cells = #objs * 27.

② 光线与场景中模型的求交

image-20220114165353415

存在的问题:Teapot in a Stadium,事实上物体模型在空间中的分布可能并不均匀!

空间划分 Spatial Partitions
  • Oct-Tree
  • Kd-Tree
  • BSP-Tree

这里以 Kd-Tree 为例,Kd-Tree 的具体实现在《数据结构》课程中已详细介绍过,这里便不再赘述。我们将空间模型首先使用 Kd-Tree 预处理,然后针对不同的光线(Query),进行如下操作:

  • 首先判断光线和最外层包围盒是否有交点,如果有那么:
    • 如果包围盒为叶子结点,直接判断光线和包围盒中模型是否相交并求交;
    • 如果包围盒非叶子结点,那么对其两个子节点的包围盒,分别判断其是否与光线有交,若有则递归地执行此过程。

kd-Tree 存在的问题:

  • 难以判断实际的物体和包围盒是否相交
    • 即使是对于物体全部为三角形的场景,也难以判断单个包围盒和单个三角形是否有交点!
  • 此外,一个物体可能出现在多个叶子结点中…
Object Partitions
  • Bounding volume Hierarchy (BVH)

我们划分的不是空间,而是物体!

image-20220116102930688

如何进行划分?

  • 沿着最长的维度来划分
  • 划分端点取中位数
    • 取三角形的重心

image-20220116103520101

使用 BVH 算法,即使包围盒可能在空间上有相交,但是我们却解决了 kd-Tree 存在的问题。

辐射度量学

辐射度量学提供了精准地描述光这个物理量的方法。

  • 光照的度量方法和单位
  • 精确地度量光的时空属性
    • Radiant Flux 辐射通量
    • Radiant Intensity 辐射强度
    • Irradiance 辐射照度
    • Radiance 辐射亮度
  • 使用物理正确的方法来计算光照
物理量的定义
  • Radiant Energy $Q$ (辐射能量,单位 J)
  • Radiant Flux (又名 Power) $\Phi = \frac {dQ} {dt}$​ (辐射通量,单位 W, lm)

image-20220116104840613

  • Radiant Intensity $I(\omega) = \frac {d \Phi} {d \omega}$,其中 $\omega$​​ 是立体角,单位为 lm/sr =: cd (坎德拉),每单位立体角的功率

立体角的定义:

image-20220116105159216

特别地,若光源均匀辐射,则我们有 $I = \frac {\Phi} {4\pi}$​。

  • Irradiance $E(x) = \frac { d \Phi(x)} {dA}$,辐照度,单位面积上的辐射通量,单位 lux.

image-20220116110821261

  • Radiance $L(p, \omega) = \frac {d^2\Phi(p, \omega)} {d \omega dA \cos \theta}$​

image-20220116111154506

辐射度(亮度)是每单位立体角和每单位投影面积上,由表面反射、发射或接收的能量。辐射度是光线的属性。

  • Radiance is power per solid angle per projected unit area;
  • Irradiance is power per projected unit area;
  • Intensity is power per solid angle;
  • That is to say…
  • Radiance is intensity per projected unit area;
  • Radiance is irradiance per solid angle, 也就是说,irradiance 是一个表面 $dA \cos \theta$接收到的能量,radiance 是该表面朝着某个 $\omega$ 立体角方向辐射出去或接收到的能量,后者具有表明方向的能力。

双向反射分布函数(BRDF)

  • BRDF := Bidirectional Reflectance Distribution Function

什么是反射?反射可以看做是物体表面吸收了照射到该处的所有能量,然后再辐射出去的一个过程。

BRDF 这个分布函数是用于描述,对于物体表面一个小面积 $dA$,接收到的来自于立体角 $d \omega_i$ 的 irradiance,会以怎样的方式被辐射出去,分布于各个 solid angle 中。即:$BRDF := \frac {dL_r({\omega _r)}} {L(w_i) \cos \theta \ d\omega_i} \rightarrow percentage$​. 即:朝某个方向的辐射度占总照度的比例。

image-20220116114348861

使用 BRDF 可以用来定义镜面反射和漫反射。此外,BRDF 还可以用来定义物体表面的材质。

于是,借助于 BRDF 的定义,我们考虑真实的光线传播。从某个点 $dA$ 向 $\omega_r$ 方向出射的 radiance,可以通过考虑所有 $w_i$ 到达这个点的照度乘以其对应的 BRDF 占比,然后求和得到。

image-20220116115205963

问题:我们考虑的入射 Radiance 可能不仅仅由光源发出,也可能是由其他物体先经过若干次反射得到…

Rendering Equation

经过推导之后,我们得出:

image-20220116151021069

全局光照 L = 直接光照 E 和间接光照的集合,其中 K 是反射算符。

路径追踪

蒙特卡洛积分

目的是为了解决定积分 $\int_a^bf(x)dx$ 问题。

做法是在 $[a,b]$​ 间随机采样足够多次,然后将足够多次的结果进行平均后作为函数均值积分。

例如,我们使用均匀采样的方式:

image-20220116153649942

更一般地,我们有:

回忆 Whitted-style ray tracing:

  • 可以做镜面反射和折射的效果
  • 遇到漫反射平面便停止

使用渲染方程,我们可以有以下推导过程:

对于非光源表面 $dA$​​​,我们有:

对 $w_i$​​ 进行 Sample,且 Sample 均匀分布于 $[0, 2\pi]$​​。于是我们可以得出:

进而,我们可以提出一种着色算法:

image-20220116164125480

然而,我们如何继续引入全局光照的概念呢?很简单,只需要考虑如果光线 $r$ 命中某个物体时的情况。也就是说,将该物体表面视为新的光源:

image-20220116164724144

我们只需要计算 $q$ 处,$-w_i$ 方向发射的 Radiance,便可以得到渲染结果。

但是这样做带来的问题是,光线的数目会发生指数爆炸,于是我们只能在采样时取 N=1,即在计算蒙特卡洛积分时取 N=1,然后仅追踪一根光线的情况。

image-20220116164911441

我们便将这种 N=1 的处理方式称为“路径追踪”。

为了降低 Noise,我们可以对像平面上的每个像素都追踪多条这样的“路径”,然后将这些路径计算得到的 Radiance 取平均值即可。

image-20220116165143374

此外,我们还需要设置 shade 过程的递归基。为此,我们可以设置最大光线弹射次数,但这样取得的效果不如使用 Russian Roulette(俄罗斯轮盘赌)。也就是说,对于某个点的着色结果,我们给定 $p$ 的概率返回 $result_{old} / p$,$1-p$ 的概率返回 $0$​,这样做我们着色结果的期望仍是 $result_{old}$!

image-20220116165744374

目前我们就得到了路径追踪算法的正确版本,即对于每个像平面上的像素点调用 ray_generation 过程,而 shade 过程则加入了这样的几何分布方式来确定光线是否能够继续生存。但是目前来说,我们的算法可能在效率上并不高,在低采样率(SPP, Samples per pixel)的情况下效果并不好:

image-20220116170133804

这是因为,如果我们的光源过小,我们需要足够多次采样,才有可能将“追踪用光线”最终命中光源。也就是说,大部分的追踪路径都是无效的:

image-20220116170327150

或许我们能找到更合适的采样概率分布…比如,对光源采样

image-20220116190243440

于是:

在之前我们假设光线可以在采样半球面上均匀射出,而现在我们将点 $dA$ 处的 Radiance 分两部分来考虑:

  1. 光源的直接贡献(不需要 RR 计算)
  2. 其他表面的反射光的贡献(使用 RR)

这样考虑后,我们得出改进版的路径追踪伪代码如下:

image-20220116190636646

此外,我们还需要考虑光源发出的光束是否可能被障碍物遮挡…

image-20220116190917657

最后,路径追踪的伪代码整理如下:

def ray_generation(camPos, pixel):
	Uniformly choose N samples from the pixel
	pixel_radiance = 0.0
	for sample in the pixel:
		Shoot a ray r(camPos, cam_to_sample)
		if ray r hit the scene at p:
			pixel_radiance += 1 / N * shade(p, sample_to_cam)
    return pixel_radiance

def shade(p, wo):

	# Contributions from the light source
	L_dir = 0.0
	Uniformly sample the light at x' (pdf_light = 1/A)
	Shoot a ray from p to x'
	if the ray is not blocked in the middle:
		L_dir = L_i * f_r * cos \theta * cos \theta' / |x'-p|^2 / pdf_light
    
    # Contributions from other places
    L_indir = 0.0
    If test Russian Roulette with probability P_RR :
        Uniformly sample the hemisphere toward wi (pdf_hemi = 1 / 2pi)
        Trace a ray r(p, wi)
        If ray r hit a non-emitting object at q:
            L_indir = shade(q, -wi) * f_r * cos \theta / pdf_hemi / P_RR
    
    Return L_dir + L_indir

材质与外观 Materials and Appearance

  • Material == BRDF!

一些材质的例子

漫反射材料 Diffuse/Lambertian Material

假设入射光的 Radiance 均匀分布:

这里 $\rho$ 可以是常数(单通道),也可以是针对不同通道定义了不同数值的向量。

抛光的金属 Glossy Material

image-20220117103604496

理想反射/折射材质

image-20220117103654766

  • 反射:反射定律
  • 折射:折射定律 Snell’s Law,注意全反射的情况
  • 能量分配:菲涅尔公式 Fresnel Term

精确的菲涅尔公式:

近似后:

微表面模型 Microfacet Material

虽然物体的表面是粗糙的,但是若从远处看,则可以将物体表面视为是平的。即对于粗糙表面来说:

  • 从远处看可以视为是平的粗糙表面
  • 从近处看看到的是高低起伏的高光表面

从远处看看到的是材质,从近处看看到的是几何。

image-20220117110551868

我们考虑这些微表面的法线的分布情况。如果其分布方差较小,则表面是 Glossy 的;而如果其分布方差较大,我们可以视其表面为 Diffuse 型。

image-20220117111415698

各向同性与各向异性材质

这是一种分类材质的方式。各向同性材质的微表面的法线分布并不具有明确的方向性,而各向异性材质的法线分布却具有,因而后者具有一些特殊的性质。

从定义上来说,后者的 BRDF 与其绝对方位角 $\Phi$ 有关。

BRDF 的性质与其测量

BRDF 的性质:

  • Non-negativity
  • Linearity
  • Reciprocity principle: $f_r(w_r \rightarrow w_i) = f_r(w_i \rightarrow w_r)$
  • Energy conservation
  • Isotropic or anisotropic

测量方法:

image-20220117112601733

  • MERL BRDF Database

知识补完

相机、棱镜与光场

  • 成像 Imaging = Synthesis 合成 + Capture 捕捉

FOV

  • 小孔成像:针孔相机

image-20220117162312506

视场 $FOV = 2 \arctan(\frac {h} {2f})$​,一般我们取 $h=36 * 24mm$ 时 $f$ 的大小作为 $FOV$ 的大小。

Exposure

  • 曝光 Exposure = Time * Irradiance

其中 Time 由快门控制,能量由光圈的大小和焦距决定。此外,ISO 感光度可以视为是后期处理,给感光的多少进行倍增。这些因素都能影响成像的亮度。

image-20220117163652644

原理:ISO 作为后期处理,对于含有噪声的信号,同时将信号放大,噪声也随之被放大,因此会显得 Noisy;F-Number(F-Stop) 一般写作 FN 或 F/N。这里的 N 可以近似理解为光圈直径的倒数。快门速度变快也会降低 Exposure,而变慢会产生模糊。

薄透镜 Thin lens

平行光入射,出射光过焦点;过焦点光入射,出射光平行;焦距可任意改变;$\frac 1 f = \frac 1 {z_i} + \frac 1 {z_o}$​。

利用薄透镜可以解释景深的问题:

image-20220117165250088

光场 Light Field / Lumigraph

  • 全光函数:我们看到的世界是七维函数

image-20220117171128615

  • 光场是全光函数在位置集合上的限制,给定任何一个位置和任何一个方向,输出光线的强度。
    • 要想描述一个发光物体对于任何位置任何方向的辐射贡献,我们可以考虑用一个包围盒罩住这个物体,只需要知道这个包围盒上任意一点对于任意方向的辐射贡献,就可以用于替代这个物体的辐射贡献。
    • 也就是说,对于任何一个物体,我们作全光函数在其包围盒上的限制,只要弄清楚其包围盒上任意一点对于任意方向的光照辐射,就可以用于替代这个发光物体。这样做方便我们进行 Query.
    • U-V 平面与 S-T 平面
    • 光场照相机

颜色与感知

  • 谱功率密度(SPD),具有线性可加性;
  • 颜色事实上是人的一种感知,它并不是光的一种属性;
  • 人感光的生物基础:视网膜上的 Cone 型细胞
  • 同色异谱现象的存在
  • 颜色的混合与匹配
    • 加色系统
  • 颜色空间与色域,RGB, XYZ, HSV, Lab, CMYK

动画与模拟

质点弹簧系统

  • 质点弹簧系统:一系列相互连接的质点和弹簧

我们再引入内部损耗摩擦力以让该系统可以停下来:

  • 质点弹簧系统组成的结构:
    • Sheet / Block / …
    • 下图为用质点弹簧系统对布料的模拟:

image-20220118112053335

粒子系统

把我们考虑的物体细分成粒子表示,然后在动画的每一帧中:

  • (如果需要) 创建新粒子
  • 计算每个粒子上的作用力
  • 更新每个粒子的位置和速度
  • (如果需要)移除某些例子
  • 渲染该帧

运动学

  • 正向运动学:通过定义各个部件之间的连接方式,给定参数(如 $l, \theta$),即可计算相应部件的位置
  • 逆运动学:可以通过拖拽等方式改变最终目标部件的位置,中间的各个部件的情况自动计算得出

逆运动学的应用: Rigging

Rigging 是对于一个角色的控制,就像是提线木偶一样,改变角色的姿态或表情…

不同角色的 Rigging 是不同的…

求解

  • Euler’s Method:简单的迭代法,十分不精确且不稳定

用数值迭代的方法解 ODE 存在的问题:

  • 误差:随着迭代步数的增加,迭代结果和真实结果存在偏移
  • 稳定性:原本收敛的结果发散,如螺旋速度场中粒子应该最终做匀速圆周运动,而实际模拟却会飞出该场

于是,我们有若干方法解决这种不稳定性:

  • 中点法 Midpoint Method
  • Adaptive Step Size 自适应步长

按照误差项判断是否将 $\Delta t$​ 继续细分…

Repeat until error is below certain threshold epsilon:
	Compute x(T) one Euler step, size T
	Compute x(T/2) two Euler steps, size T/2
	Compute error = || x(T) - x(T/2) ||
	if (error > threshold):
		T <- reduced(T)
	else:
		break
  • 隐式欧拉方法

这种方法提供了更好的稳定性,下面我们就进行稳定性的定义:

  • 局部截断误差 Truncation Error
  • 累积误差 Accumulated Error

我们一般研究误差就是研究这两个误差和我们所取的 $\Delta t$ 的阶数的关系。

推导可以得出,隐式欧拉方法:

  • Local Truncation Error: $O(h^2)$
  • Global Truncation Error: $O(h)$
  • $h$ is the step size, i.e. $\Delta t$​.

误差是 $O(h)$ 的意思是说,如果我们将步长缩小到原来的一半,那么误差期望也缩小到原来的一半。

Runge-Kutta Families 中的 RK4 方法广泛得到运用,是一个 4 阶的方法。

  • Position-Based / Verlet Integration,一种不是基于物理的方法
    • 这种方法快速简单,但是可能不会遵守能量守恒等物理定律

下面举一个简单的 Position-Based 方法的例子,即渲染如下图片的例子。

image-20220118165158591

关键想法如下:

  • 将水视为是很多小刚体球组成的
  • 认为水的密度是不变的,即这些小刚体球是不可以被压缩的
  • 也就是说,一旦某处水的密度改变了,就应该通过重新分布不同区域的刚体球的数量来“矫正”这个变化
    • 需要知道水的密度场的梯度!
    • 这个水的密度场是由刚体球所在位置决定的…
  • 如何矫正?Gradient Descent!

模拟方法的总结:

  • (质点法)拉格朗日方法,将物体细分成一个个质点
  • (网格法)欧拉方法,将整个空间分为不同的网格,考虑空间网格中存在的物体随着时间的变化