写在前面
上图是计算机图形学领域里一篇经典论文的“预告图(teaser image)”,预告图通常是论文的结晶,放在开头用来吸引读者的。一些读者看到这张图片可能会想:“这张照片有什么吸引人的”?但是如果我说这不是照片,而是由计算机渲染出来的图片呢?
计算机图形学论文的预告图一般是由论文中提出的技术渲染出来的,上图也不例外,但是它看起来太真实了,细节非常丰富(图中有标明),简直可以以假乱真!这种达到照片级别的渲染就是当下流行的真实感渲染(photorealistic rendering),要达到真实感渲染的效果,整个渲染过程需要“符合”物理学原理,所以我们也称它是基于物理的渲染(PBR — Physically based rendering)。
那么要如何做到 PBR 呢?
我们都知道人之所以能看到五彩缤纷的世界是因为人眼能够感光成像,光照到物体,物体会吸收一部分光也会反射一部分光,人眼接收到物体反射的光就是物体对外展示的色彩;所以为了做到 PBR ,我们需要在计算机渲染中模拟这个过程。PBR 涉及的内容非常多,为了便于理解,我将 PBR 的要素简化提炼一下:
基于物理的光照
基于物理的材质
基于物理的渲染方法
我们认为全局光照就是基于物理的光照,材质可以由基于物理的双向反射分布函数(BRDF)来表示,基于物理的渲染方法当然就是大名鼎鼎的渲染方程(Render Equation)。
本系列文章将以实时全局光照为切入点来介绍不同时期人们提出的精妙的算法理论,看看这些理论是如何解渲染方程的,最后还会介绍虚幻引擎(UnrealEngine)中的全局光照背后是如何应用这些算法的。
本篇是实时全局光照技术的开篇,将介绍全局光照的概念,怎么理解实时全局光照中的“实时”;本系列文章主要介绍的是光照相关的技术理论,但是避免不了牵涉 BRDF 和 Render Equation 相关内容,所以在进入系列篇章之前我会对这些内容做一些简单介绍,可以作为前置阅读资料,也可以在后面的篇章中遇到了再回头来看。
全局光照
上图其实也不是真实照片,而是由计算机渲染出来的 3D 场景图片,但是看上去非常真实对不对。我们再来看看下面这张图片:
这张图片看起来也不错,不过总感觉缺有点违和,问题出在哪里呢?
我们可以注意一下两个图中标注出来的 p 点,图2中的 p 点明显要暗上许多(其实是纯黑色的);我们再仔细观察下,其他没被“阳光”直射的地方都非常暗,这显然不符合物理规律。图1 就好很多,p 点和其他未被光源直射的点虽然会暗一些,但并非纯黑色而是有一定的亮度,造成这个区别的原因就在光照上,图1 应用了全局光照(Global Illumination),而图2 只有直接光照(Direct Illumination)。
注:光源直接照射到物体表面被称为直接光照,被光源直接照射的物体表面再照亮其他物体被称为间接光照(Indirect Illumination),而全局光照则是直接光照和间接光照的叠加:Global Illumination(GI) = Direct Illumination + Indirect Illumination。
实时全局光照
我们知道了全局光照可以带来非常真实的渲染效果,而本文的主题是实时全局光照(Realtime GI),这个实时要怎么理解呢?
在计算机图形学中,一般大于 30FPS 的渲染被称为实时渲染,10FPS 左右的我们称为可交互渲染,再慢的就是离线渲染。离线渲染主要用于电影行业,一般可以通过 Monte Carlo Path Tracing 等算法达到非常接近现实世界的效果,我们甚至可以认为它就是 Ground Truth(基准真相) 。电影级别的离线渲染,一帧可能需要渲染几个小时甚至几天,而实时渲染要求一帧至少要在 1/30 秒(约 30ms)内完成,可见要做到高质量实时渲染(既有优质的渲染效果并且要做到实时)的挑战有多大。
实时全局光照就是高质量实时渲要解决的一大挑战,本文会带大家领略一下在实时全局光照研究方向上一些鼎鼎大名的算法,同时也会介绍其中一些算法在 UnrealEngine 中是怎么应用的。
上面提到 Global Illumination = Direct Illumination + Indirect Illumination ,Indirect Illumination(间接光照)我们前面讲过,本质上是由非光源反射的光带来的照明;我们可以想象一下,由间接光照照亮的物体是不是还会照亮其他物体,只要被照亮的物体说明他们都对外反射了光线,这些光线又会照亮其他物体,物体之间还会存在相互照亮的情况,现实世界的光照反射实在是太复杂了,我们需要先做一个抽象的定义,再根据定义来解决问题。
注:间接光射出的光线打到物体后直接反射到人眼,我们称为一次弹射(one-bounce),如果间接光在场景中经过多次反射再进入人眼我们称为多次弹射(multi-bounce)。
我们可以做如下定义:N-bounce global illumination = Direct illumination + N-bounce Indirect Illumination,即一次弹射的全局光照等于直接光照加上一次弹射的间接光照,同样的,多次弹射的全局光照等于直接光照加上多次弹射的间接光照。
根据上面的定义我们再来对比下面的几张图片:
我们可以看到 Direct Illumination 和 One-bounce Global Illumination 的差别非常大,
而 One-bounce 和 Two-bounce 还有 Sixteen-bounce global Illumination 的差别已经不那么明显了。
我们前面讲过在电影行业中通过离线渲染一帧需要几小时甚至几天时间,其实就是用到了 Multi-bounce Global Illumination。每多一次 bounce 带来的计算量是指数级增长的,渲染时间也会大大延长,这在实时渲染中是不能接受的;而我们又发现 One-bounce GI 虽然没有那么真实,但效果也还不错,所以我们第一个大胆的近似就来了,在 Real-time GI 中,我们只处理 One-bounce Global Illumination(Direct Illumination + One-bounce Indrect Illumination)。
注:在实时渲染领域,由于硬件的限制和对时间的极致要求,通过近似(approximate)去表达真实的方法会很常见,有时候人们会根据观察提出假设来近似,有时候会通过数学中的不等式或约等式来近似。
系列篇章
限于篇幅,实时全局光照技术会拆为下面几个篇章,分别介绍:
直接光照:介绍光源、环境光(Environment Light,不是指 AO(Ambient Occlusion) 中的环境光)的概念以及在实时渲染领域如何带入渲染方程进行计算;
间接光照:从 RSM(Reflective Shadow Map) 开始,介绍一些在实时渲染领域有名的间接光照算法原理和优缺点;
阴影:有光的地方就有阴影,阴影篇章会介绍常见的阴影生成算法;
UnrealEngine 中的光照技术:最后我会介绍一下在虚幻引擎中是如何应用前文提到的算法;
直接光照
TBD
详见《[WIP]实时全局光照技术(二)——直接光照》
间接光照
TBD
详见《[WIP]实时全局光照技术(三)——间接光照》
阴影
TBD
详见《[WIP]实时全局光照技术(四)——阴影渲染》
UnrealEngine 中的光照技术
TBD
详见《[WIP]实时全局光照技术(五)——UnrealEngine 中的光照技术》
PBR 理论资料
本章节作为实时全局光照技术的补充阅读资料,可以在后续篇章中遇到了再回来查阅。
辐射度量学 Radiometry
PBR 需要用到基于物理的光照,我们首先要把光照通过数学表达出来,这里我们用到了辐射度量学的一些概念。
辐射通量 Radiant Flux
我们都知道光照是一种能量(energy),能量用 Q 表示单位是焦耳(joule),但是在图形学中我们一般不用能量来描述光照,而是用到了辐射通量或者辐射功率这个概念,它是单位时间的能量(joules per second),辐射通量用 Φ 表示单位是 W(atts),也就。其公式定义为:
,dt 表示单位时间。
辐射强度 Radiant Intensity
辐射强度是单位立体角的辐射通量,用 I 表示,单位是 candela ,辐射通量我们知道,再来看看立体角的定义。
立体角定义
以观测点为球心,构造一个单位球面;任意物体投影到该单位球面上的投影面积,即为该物体相对于该观测点的立体角。因此,立体角是单位球面上的一块面积,这和“平面角是单位圆上的一段弧长”类似。
立体角公式
在球坐标系中,任意球面的极小面积为:
因此,极小立体角(单位球面上的极小面积)为:
所以,立体角是投影面积与球半径平方值的比,这和“平面角是圆的弧长与半径的比”类似。 对极小立体角做曲面积分即可得立体角:
知道了立体角和辐射通量,我们可以得出辐射强度的公式表达为:
,dw 表示单位立体角。
辐照度 Irradiance
辐照度是单位面积的辐射通量,用 E 表示,单位是 W·m−2 。公式表达为:
,dA 表示单位面积。
辐射率 Radiance
辐射率是单位面积单位立体角的辐射通量,用 L 表示,单位是 W·sr−1·m−2 。公式表达为:
双向反射分布函数 BRDF(Bidirectional Reflectance Distribution Function)
BRDF 的定义是反射光和入射光的比例,前面我们学习了光照的数学表示,那么 BRDF 我们也可以通过公式表达出来了:,其中 fr 就是 BRDF,
表示出射光 Radiance,
表示入射光 Irradiance。
双向反射分布函数是用于描述物体表面材质的,这里的双向指的是视线方向和光照方向,也就是上面渲染方程的示意图中标注的和
,下面我们用实际的例子来看看为什么物体的材质跟
和
有关联。
如果视线方向和光照方向我们都不考虑,那么看到物体就会感觉非常平(面),没有立体感,就像这样:
我们把光照对物体表面颜色的影响加上看看,我们得先知道光照是怎么影响物体表面颜色的。
兰伯特余弦定理
人们观察发现,在现实世界里同一个物体不同的位置的明暗程度是不一样的,如果光源被移动了,物体的明暗位置也会随之改变,人们很早就在素描中用到了这个发现。著名的兰伯特余弦定理( Lambert's cosine law )给出了理想漫反射模型下 BRDF 的数学计算推导,兰伯特余弦定理假设没有光照能量损耗,所有光照都被均匀反射,我们把出射光也可以类比成半球面上所有方向的入射光,因此在半球面积分时也需要考虑出射光与法线的夹角,即:(注意等式两面的
不同,
表示出射光方向,
表示入射光和法线的夹角),我们带入到 BRDF 的基本公式中可得:
;
前文提到立体角的定义,带入上述公式得
;
解一下三角函数积分可得:,单位是
。
这个推导过程中假设了没有光照被吸收,但实际情况不会是这样,因此我们还需要带上一个系数 c ,最终公式为:。
我们把这个公式带入到渲染看看效果:
兰伯特模型认为物体表面的明暗跟光线入射角度有关,我们通过这个模型去做渲染已经能看到物体的立体感了。后来人们发现兰伯特模型的明暗变化太快了不符合直觉,于是把 -1 到 1 的明暗色阶变成 0 到 1 的范围。
上面经过调整明暗色阶之后的模型叫做半兰伯特(Half-lambert)模型,效果看上去会好不少。
Phong/Blnn-Phong 模型
不过我们发现这个模型没有办法去描述一些光滑的物体,我们可以回想一下,对于较为光滑的物体,我们会看到一片明显高亮的区域,这个区域也会随着人们的视角变化。因此人们在渲染模型中引入了视角方向,比较出名的模型有冯(phong)模型和布林冯(blnn-phong)模型,效果如下:
phong 模型有漫反射和镜面反射两个部分,漫反射部分还是使用兰伯特模型,镜面反射部分则是根据入射光方向(lDir)在入射点法线方向(nDir)的镜面反射方向(rDir)和视角方向(vDir)的夹角计算得出。但是我们观察到不同物体的高亮区域的面积不同,所以 phong 模型的镜面反射部分在出射光方向和视角方向的点乘运算外还加了一个乘方,我们可以通过调整乘方的指数来控制高亮区域大小,乘方的指数越大高亮面积越小,反之则越大。具体公式如下:
和
分别表示出射光和入射光
和
分别表示漫反射系数和镜面反射系数
表示 lDir 和 nDir 的夹角
表示 rDir 和 vDir 的夹角
是 rDir 和 vDir 夹角余弦的乘方,用于控制高亮区域的大小
使用 phong 或者 blnn-phong 模型我们通过调整、
和
能够实现不错的渲染效果。但是这几个参数都是根据人们的经验给出的,并没有基于物理原理,渲染结果自然也没那么真实。
微表面模型
直到后来有人提出微表面模型(microfacet model),微表面模型认为物体的表面是由非常多的微小的表面形成,对于每个微表面我们认为它只会进行完美的镜面反射。物体表面的材质不同,其微表面的法线分布(Distribution)也各不相同,越光滑的物体表面,它的法线分布越集中,对应的微表面反射的光线也就越集中,这就会形成我们看到的高光;与之相反的是,越粗糙的物体表面,它的法线分布越分散,其高光的面积也就越大,对于非常粗糙的物体表面,我们有时候都很难看到高光了。
基于微表面的模型我们不得不提一提 Cook-Torrance BRDF,Cook-Torrance BRDF 也分漫反射和镜面反射部分,跟前面的 phong 模型一样,漫反射和镜面反射根据材质不同有不同的系数和
。漫反射部分沿用了 lambert 模型,在镜面反射部分则基于物理规律分为了三项:
F(Fresnel 项):光线入射方向不同,其在物体表面发生反射和折射的比例也不一样,一般情况下,光线入射方向越接近物体表面,物体呈现的反射越高。
D(法线分布函数):描述粗糙度对法线分布影响的函数;
G(几何遮蔽函数):也和粗糙度相关,越粗糙的物体,光线在入射和反射过程中都可能会被凹凸不平的表面遮挡,这可能会让物体显得更暗一些;
其镜面反射部分具体公式如下:
;
我们前面提到的漫反射和镜面反射系数
同样也由菲涅尔方程决定,限于篇幅,我后续会独立一片文章来介绍F、G、D项的推导过程,以及金属度的引入缘由,这里先直接给出实时渲染中常用的反射方程(简化的渲染方程)近似结果:
基于 Cook-Torrance BRDF 后来又有一些有名的法线分布函数,例如 Beckmann、GGX,这些 NDF 让 BRDF 更加基于物理,也能够渲染出更加真实的图片。
渲染方程 Render Equation
在辐射度量学部分我们知道了光的数学表达以及光的传播运算,这些将在渲染方程的表示和求解中使用到。
:从
方向看过去 x 点的出射光;
:从
方向看过去 x 点的自发光;
:x 的 BRDF (双向反射分布函数),由物体材质属性确定的入射方向到出射方向光的反射比例;
: 从
方向入射的光,这里乘以
是考虑了光照方向和物体法线有夹角有能量损失,我们很多情况下也会把
放到
里,这样渲染方程就没有
项;
:光照方向
是否能照射到 x 点,如果不能则整个积分项结果为 0 。
渲染方程简单来说就是对于任意着色点 x,我们眼睛从方向看过去的光照
等于 x 点的自发光加上对「 x 点半球面(
)所有入射光跟 x 点材质计算值」积分之后得到的光照。
有向距离场 SDF(Signed Distance Field)
SDF 表示的是空间中任意点到离它最近的物体表面的距离,SDF 是有向的,如果这个点在物体内 SDF 的值就是负值,否则 SDF 的值就是正值。SDF 用处很广,它既能作为光线步进时每一步距离的依据,还能够用作几何的“隐式表达”。
TO BE CONTINUED