致渲染(rendering)爱好者的一封信

各位渲染爱好者:
你们好!

您可能是一名游戏引擎/渲染器研发工程师,游戏开发者,技术美术,图形学研究者,老师或者学生等,您的工作可能涉及影视动画制作,游戏(引擎)开发,物理仿真,医学成像,室内设计,虚拟现实,以及其他视觉相关的工作等,但不管怎样,你们都有一个共同的愿望,那就是希望了解怎样将一个数字场景渲染成一幅符合物理的,非常逼真的,令人赏心悦目的图片,就像本文的封面图片,这幅图片来自皮克斯的电影《寻梦环游记》,也许您观看过这部电影,并曾经或者还在惊叹于它使用的图形技术,您能想象那个梦中的场景有826 5557个点光源吗?
那么我是谁呢?可能大部分朋友还/并不认识我。

但是很多朋友可能听说过我写的一本即将出版的关于渲染的图书:《全局光照技术:从离线到实时渲染》,这是一本纯聚焦于渲染的图形学图书,我花了三年多全职的时间去写作这本书。我于2016年就开放了一些这本书的试读内容,到目前为止百度网盘的文件下载量超过了2000多次,还不包括一些QQ群内无法统计的数字;我于2017年中发起了半本草稿书的众筹(《全局光照技术》- 原来图形技术的世界美如她所创造的世界),甚至有将近500多人购买了一本只包含一半内容的同时包含很多未矫正文法错误的半成品图书,这在中文出版史上可能是第一次;我再次于2017年底发起全书的正式预订(《全局光照技术》出版在即!揭秘工业中最前沿的渲染技术 – 摩点 – 文化创意众筹社区),在距离正式出版还有长达半年之久,有800多名读者就已经预订了这本图书!

那么今天我想与您说些什么呢?坦白讲我是为了宣传新书,这个我得首先向您坦诚,因为写作了三年,我当然希望它有一定的市场,每名作者也希望自己的创作能够被接受和认可。但是今天,我更想与您讨论的内容是:我是怎样从零开始学习计算机图形学知识的?我想向您描述我心中的图形学世界,我所看到的图形学逻辑知识图谱,以及我给您的一些学习建议!

我的图形学学习历程

我并不是计算机专业毕业,在大学也就是自己学了点编程知识(那时主要是C#和Ruby on Rails),以及旁听了一点计算机专业的基础课程,毕业后的头两年也就是做企业软件开发,那时候其实我还没有一点关于计算机图形学的概念,甚至我在大学基本上不玩游戏。

我进入游戏开发行业是一个偶然的机会,那时候Cocos2d-x团队希望与我所在的OpenXLive公司合作,将其移植到Windows Phone平台上,这个项目也是我加入OpenXLive的原因,那个时候我还在另一家公司,我跟Cocos2d-x的创始成员之一(我的好朋友)杨文生先生以及OpenXLive的老板在一起吃了次饭,商定由我来负责这个项目的移植。

其实那个时候(2011年底)我还没有一点关于3D渲染的概念(所以您可以猜到我全部的计算机图形学知识是从2012年才开始学习的),我之所以被委任这个项目,主要是因为我那时C#还算比较不错,以及他们对我做事态度的认可。后来我进入新公司后,我带领2名实习生,在Cocos2d-x团队的协助下,大概一个月左右的时间发布了一个预览版,然后大概3个月发布了正式版(cocos2d/cocos2d-x-for-xna),您可能会觉得仅仅是语言的移植会很简单,但其实这仍然涉及到很多工作,如果你不去学习了解3D知识,会遇到很多困难。

cocos2d-x-for-xna是我进入3D领域的一个时间点,尽管那个时候移动游戏开始逐渐兴起,很长一段时间我还是没有找到对游戏开发的激情,还记得我说过我在整个大学期间几乎没有怎么玩过游戏,我确实觉得玩游戏会浪费时间,所以Cocos2d-x项目之后我还是回到了传统的应用和企业开发。

直到后来有幸玩到了一个游戏:Superbrothers: Sword & Sworcery EP(Sword & Sworcery – NEWS),我才真正被游戏的魅力征服,从此开始全身心投入游戏行业,开启了我一发不可收拾的计算机图形学学习之旅。

后面的路可能给你们中的大部分朋友一样,疯狂地购买和阅读各种游戏开发的书,OpenGL图形编程之类的书等,到后来写作这本《全局光照技术》时大量阅读渲染方面的论文。我将把这些学习经验和方法留到最后一部分介绍。

我心中的渲染知识图谱

如果你看过 @Milo Yip 的 游戏程序员的学习之路,仅考虑图形部分,这里列出的还是比较优秀的图形学图书,也有60多本;如果你到《Real-time Rendering》官网查看一个图书列表(Real-Time Rendering Graphics books Page),这里甚至列出了多达数百本渲染相关的图书;如果你搜索渲染相关的论文,所有论文的数量甚至是以万计数的。

面对如此浩瀚的知识和技术,我们该如何着手,从哪里开始,这些不同的知识通向哪里,怎么判断你走在了正确并且最快捷的道路上?现在我就视图从我的知识系统出发,给您描述一副渲染的知识图谱,以帮助您更高效地作出选择和学习。

渲染的问题,本质上是一个积分的问题。对于无法通过解析的方式求解的积分,我们通常使用一些数值方法,最常用的就是蒙特卡洛方法,它通过在被积函数的定义域内随机采样,并通过将该样本代入到函数中计算其贡献值来近似该积分的计算。积分的结果是一个数值,但是如果我们存储了函数各个定义域处的贡献值,那么我们就能还原被积函数的分布,在渲染中也就是最终渲染图像的像素颜色值,这就是渲染的原理。

然而,摄像机描述的图像对应分布函数的形式并不是已知的,我们所要想了解的每个像素的颜色,源于光线从光源发出,然后在空中传播,并经过与场景表面的一系列交互,例如反射或折射,最后进入摄像机的过程,因此我们的被积函数的形式隐藏于这种光照传输当中,因此渲染的问题本质是也是一个光照传输的问题,为了描述被积函数的形式,我们需要研究光照的传输。

最直观的描述光照传输的方法就是光线追踪,它是表述光子从光源出发到达摄像机的整个传输过程,我们记录下每个到达摄像机的光线的能量以及其在图像空间中的位置,那么我们就得到了整个图像的分布。因此光线追踪的思路很简单,就是在图像空间中每个位置处发射一条光线,然后计算该光线的光照贡献。我们也称一条光线为一个样本,一条完整的光线也称为一个光线路径,因此跟踪这个光照传输的过程也称为路径采样,基于路径采样的光线追踪算法也称为路径追踪。

然而,一个数字场景通常包含了太多复杂的细节,以至于我们需要非常巨量的光线又能够比较真实的近似场景的实际视觉特征,比如每一帧可能需要数以亿计的光线,这样根据使用算法的不同,渲染一帧可能需要数分钟至数小时甚至数天的时间。

因此,路径追踪技术的主要聚焦点就在于寻找更有效的路径采样方法,因此光照传输的问题本质上又是采样的问题。在采样中,一个样本是一个随机数,由于随机数本身具有方差,因此这导致整个积分的估计也具有方差,并且在蒙特卡洛方法中,我们需要4倍多的样本数量才能换来2倍的方差减少,因此在路径采样问题中,我们又主要将关注点集中在减少估计的方差上。

方差是怎么产生的呢?首先要明白,方差是一种群集属性,它是指一系列随机样本的平均值与每个样本误差的综合。蒙特卡洛方法的直观形式,其实是根据某个分布函数采样来产生基础样本,然后将这些样本代入带被积函数以计算样本的贡献值,所有的贡献值最后被平均,最后通过统计某个区域内样本的数量来估计该区域的函数值,所以如果这些样本的贡献值越是相似或接近,那么估计的方差就越小。

因此,理想的方法就是使用图像的分布函数为采样函数,这样每个样本的贡献值将是绝对相同的,估计的误差为0。然而这确实不可能实现的,因为被积函数的分布正是我们试图去求解的结果。但是尽管我们无法知道整个图像分布函数的显示形式,但是我们知道它的部分表达式,例如BRDF分布函数,如果选取这些部分子函数作为采样的分布函数,那么估计的方差也可以被大大减小,这就是所谓的重要性采样,它几乎被用在所有需要采样的地方。

与重要性采样方法紧密相关的是复合重要性采样,这种方法基于这样一种理论:即对于同一个样本,它可以使用不同的分布函数进行采样,在上述的重要性采样方法中,函数的不同部分通常对其中的一些区域有着更好的拟合,但是对另一些区域拟合效果就会差得多,由于同一个样本可以来自于不同的分布函数,因此如果我们使用对个分布函数进行采样,然后将它们组合起来,让来自不同分布函数的样本去更好地拟合相应的函数部分,那么整个估计的方差也会被进一步降低。

那么来自两个不同分布函数的样本应该怎样被组合在一起呢?前面已经说过,蒙特卡洛方法的原理是假设每个样本的贡献值是相同的,最后仅仅涉及对样本数量的统计,因此如果我们使得来自不同分布函数样本的贡献值是相同的,那么它们就可以被放到一起进行统计计数,毕竟最终我们需要的只是数量么,并不在乎它是通过什么分布函数进行采样的,这就是复合重要性采样方法的核心。

需要注意的是,在路径采样中,一个采样分布函数是与特定的路径长度相关的,对于不同长度(或深度)的路径,我们通常需要使用不同的采样方法。另一方面,在双向路径采样中,一条路径中间会有一条子路径时通过直接连接(而不是采样)得到的,对于一条已经采样完毕的路径,我们可以直接通过解析的方法得到该路径对应的多个采样分布函数,这可以仅仅通过在不同的子路径之间执行连接操作即可,这个过程甚至不涉及其它昂贵的路径追踪过程,例如直线光线与场景的相交计算。

尽管重要性采样方法能够大大降低估计的方差,但是运用在渲染中仍然面临着另一个非常困难的问题:由于图像的分布函数不是已知的,因此它依赖于光线追踪来执行路径采样,然而由于路径是随机采样的,这使得一些路径样本很难被采样到,例如,两个被强隔离的房间,中间只有很小的一个通道,其中一只有一间房间内有光源,在这种情况下,另一件房间唯一的光照来自于那个狭小的通道,而要想渲染该房间内的图像,每一条光线都必须要经过那个通道才能达到光源。对于这种场景的渲染,大部分随机采样的路径都会无效,使得估计收敛的速度非常慢。
因此,对于有些场景,重要性采样方法仍然是无效或者低效的。离线的情况下,我们会需要一个完全正比于图像分布函数的采样函数才能够克服这样的问题,而梅特波利斯算法正是这样的一种采样方法,这种方法可以不要求事先知道被积函数的形式,它只需要我们能够计算每个样本的函数值,然后通过比较两个相邻样本的函数值,最后就能让样本的分布正比于目标被积函数。这种方法的的原理,就是利用了一个稳定状态空间的状态转移原理,在一个处于稳态的系统中,某种度量在各个状态之间的转移在宏观上是不变的,因此我们只要知道了每两个状态之间的转移关系,那么我们就可以在各个状态之间执行转移而保持整个系统的平衡。

梅特波利斯算法就是利用了这样的原理,尽管我们不知道被积函数的形式,但是我们知道每个样本的函数值,通过对当前样本执行一个扰动以产生一个新的样本,并通过比较该新的样本在其位置处的函数值,我们就知道这个新的样本是否位于函数区域内,通过这种比较来选择或拒绝该样本,在多个样本的效应下,就相当于我们会按照函数的分布来产生下一个样本,这就相当于产生了一个从当前位置到下一个位置的复合被积函数的转移函数,因此梅特波利斯算法能够产生复合被积函数的样本,这样的方法在用于克服上述的采样问题。同时由于采样函数正比于被积函数,因此其估计的方差也大大降低。

双向路径追踪算法有一个主要的缺陷,那就是当两条来自光泽表面的子路径相聚于一个漫反射表面时,它们几乎无法连接成为一个完整路径,这种路径也就是经典的焦散效果,我们也几乎从发从漫反射表面随机寻找到一个朝向一个光泽表面的方向,这样的路径几率太低,以至于在我们有限的时间要求下可以认为是不可能的。为了克服这个问题,随机的方向采样显然无法再被使用,于是人们提出一种称为光子映射的方法,这种方法的分为两个渲染通道,第一个通道从光源出发,其首先经过与光泽表面的交互,最终落于第一个漫反射表面上,其光出的光线不再是携带辐射亮度值,而是一个能量密度值,因此这条光线称为一个光子,这些光子最终落于场景中的漫反射表面上,当足够数量的光子散落于漫反射表面时,我们就可以使用回归分析的方法拟合出漫反射表面的光子密度分布,从而可以得出任意位置处的能量密度。

当漫反射表面的任意位置都知道能量密度时,后续的路径追踪通道,来自光泽表面的路径就不需要与其它路径“连接”,因为它击中的任何位置都可以计算出光照贡献。通过这种方式,光源子路径与摄像机子路径之间不再是“连接”,而是以一种“合并”的方式生成一条路径,一条摄像机子路径实际上与该点附近的多条光源子路径“合并”产生,尽管每条合并的路径的光照贡献被非参数回归使用的核函数加权从而大大变小,但是这种方法巧妙地解决了焦散路径的采样,并且由于第一通道生成的光子图可以被重用,这也在一定程度上弥补了路径贡献率低的问题。

我们以及介绍了目前为止离线渲染领域三大经典采样方法:(双向)路径追踪,梅特波利斯光照传输,以及光子映射,它们分别具有各自的优势,能够删除处理特定环境下的路径采样。那么这三种方法能不能被组合在一起呢,答案当然是可以的,因为上述每一种方法都是一种路径采样的方法,让我们得到一个样本时,我们能够按照复合重要性采样的思路把他们全部组合在一起,这样我们的整个渲染流程就有了一个统一的算法架构。

使用更好的采样方法就足够了么?显然还不够,上述这些方法的重心在于减少估计的方差,但是我们仍然需要数以亿计的光线,毕竟场景包含那么多的细节,上述的方法使得样本的分布更加符合图像的分布,这是依靠样本的数量正比于图像的分布来实现的。然而考虑图形分布函数的那些平滑的区域,这些区域由于频率变化极低,因此我们只需要在这样平滑的区域适应极少的样本就能很好地近似图像分布。

因此路径采样的另一个方向是分析图像的频率分布,使得我们仅需要对高频的区域适应更密集的路径样本,而在平滑的区域减少路径采样的样本,这种方法显然能够大大提高路径追踪的效率。

这方面的方法包括频率域分析,流形探索,和自适应采样方法,前两者这里不再详述,请读者日后参考《全局光照技术》,里面包含大量的篇幅,我们这里仅说明一下比较好理解的自适应采样方法。

只适应采样方法的思路很简单,整个采样采样过程是迭代式的,首先算法根据某种基础采样方法得到少量的路径,例如上面介绍的那些方法,这些少量的路径样本形成比较高噪的图像分布,由于这些样本可以看做一些已知的函数值,因此我们可以用它们来拟合出一个“真实”的分布图像,这正是回归分析的思路,最后我们从这个拟合的图像分析其频率分布,然后在下一个迭代阶段,对那些高频的区域放置更多的样本,而减少那些低频区域的样本数量,通过这样的方式来大大减少样本的数量。并且这样的拟合随着样本数量的增加而越来越精确。

更多关于自适应采样的介绍可以参见我的另一个回答:光线追踪渲染中遇到了自适应方法吗?

对于上述的路径采样,如果场景中的物体都是绝对光滑的镜面表面,那么路径在传输过程中的轨迹就绝对由反射和折射定理决定,采样过程能做的事情就是随机决定光线从摄像机或者光源发出的方向。

然而,当我们开始考虑表面的粗糙度时,事情就变得复杂起来!

首先我们需要明白的是,粗糙度到底是什么?它指的其实是表面的微观结构,那么要明白这种微观结构,以及怎样表述这种微观结构,我们需要明确一个“像素”的意义。

在渲染中,像素并不仅仅是指物体表面某个点的位置,当我们通常在讨论“像素”概念这个概念的时候,我们更多的是在描述它的位置坐标,然而像素最重要的特征其实是它的尺寸,当我们在对一个像素进行着色的时候,其实我们是在计算物体表面某一个尺寸范围内的平均颜色,随着距离摄像机的距离发生改变,一个像素的尺寸范围也在发生着改变,只不过因为有了如多级纹理过滤这样的硬件特征,我们在概念中忽略了像素的尺寸特征。

那么像素的尺寸是什么,它是跟图像的分辨率,以及我们的应用程序所能处理的几何尺寸相关的,当我们将摄像机的分辨率确定,并且选择了摄像机所能覆盖的空间面积时,像素的尺寸就被确定下来,在这个尺寸之下,一个像素就是应用程序所能计算的最小范围单元!

从这里可以看出,像素的尺寸是在发生变化的,因此一个像素的尺寸不能代表表面的微观结构尺寸,要想让一个像素对应这种微观结构尺寸,屏幕的分辨率就会变得非常巨大,而我们的计算量也变得非常惊人。

那怎样克服图形应用程序的着色尺寸与物体表面微观结构尺寸之间的不对等呢?答案就是使用一中抽象的概念来描述微观结构,也就是在描述一个像素所覆盖的那些微观结果时,我们使用一个关于这些微面元的分布函数,该分布函数说明,当光线从某个方向进入这些表面时,它有多少几率从观察反向反射出来,这就是Microfacet BRDF的本质。

Microfacet BRDF是一些经验模型,它们是对物体真实微观结构的分析得出的一些近似模型,这些模型可以以简单的方向函数的形式表述,例如游戏当中比较常用的GGX模型。Microfacet BRDF通常使用三个部分的乘积来表述微面元的反射特征:菲涅尔系数,微面元的法线分布函数,以及考虑微面元之间相互遮挡的遮挡函数,遮挡函数的出现是为了近似微面元的空间结构,因为法线分布函数是基于平面的,即它假设所有的微面元处于同一个平面上,因此缺乏微观结构的凸凹特征。

由于同一种物体的表面微观结构通常都是均匀的,所以我们可以认为表面的每个像素都可以使用同一个Microfacet BRDF函数进行表述,因此每个表面的反射特征就仅仅被记录在像素着色器中的一个数学公式,这大大避免了表述物体表面微观结构的内存开支。

Microfacet BRDF的思想其实不光可以用来表述这种小于像素级别的微观结构,它其实提供了一种基本思路:即当应用程序处理的单位尺寸远远大于其覆盖的实际尺寸,并且这些实际的“微小”尺寸的图形特征非常重要时,我们均可以用一个表述这些“微小”尺寸图形特征的分布函数,来为这个宏观的应用程序处理尺寸提供一个代理表述。

举个例子,在VXGI中,我们处理的是一个个体素,一个体素表述的是一个3D的几何区域,这些区域的尺寸可能远远大于一个像素的尺寸,这就是我们选择使用体素的原因,我们通过增加一个处理单元所能处理的空间面积(或体积),来减少计算量。这也好比我们使用像素级别的处理单元,来计算微面元级别的反射特征。因此在这里,为了能够反映每个体素内的表面的光照特征,我们也将该体素内所有像素的法线分布联合起来,组成一个宏观的法线分布函数,这就是VXGI中能够使用体素来渲染表面的精妙所在。

有了上述关于使用一个分布函数来描述着色级别的“微观结构”分布的思路(这里“微观结构”不再是指表面真实的微面元结构,而是指相对于着色尺寸来讲,那些小得多的尺寸,例如相对于一个体素来讲,这种微观结构可能就是一个像素),我们就会思考,能不能将这些分布函数与物体表面的几何表述结合起来,例如当物体离摄像机很近时,我们使用表面实际的微面元分布;当物体离摄像机较远一点时,我们能否将表面的顶点级别的分布与Microfacet BRDF结合起来,形成一个新的分布函数;当物体离摄像机更远时,我们能够把场景中物体网格之间的几何分布或者网格的LOD数据与Microfacet BRDF结合起来,形成一个更大范围的分布函数。这种几何表述与Microfacet BRDF的组合,不仅大大提升了计算的效率,还能够提升图像的精确度。

所以,你现在明白“像素”的意义了吗?同时明白了分布函数相对于应用程序处理的范围尺寸之间的关系了吗?更多关于Microfacet BRDF的知识,可以参见我的另一篇文章:More DETAILS! PBR的下一个发展在哪里? 

当我们把目光转向实时渲染时,实时的积分计算就变得非常奢侈,实时的光栅化管线甚至只考虑直接光照,而将间接光照留给其它的一些近似方法,下面我们将讨论实时渲染中计算间接光照的两种重要的基本思路。

首先说明一下,当前的大多数实时渲染中的全局光照算法,都大大地依赖于环境光照贴图,环境贴图是将摄像机置于环境中的某个位置,然后渲染整个360度的场景,这个环境光照贴图最后被用于提供间接光照,且它被认为是与位置无关的,因此对其采样是只需要提供方向就行。

所以,当我们需要计算一个表面的间接光照时,我们需要做什么事情呢?它实际上就是表面的BRDF分布函数与环境贴图光照乘积的一个积分,想象一下,每个像素都需要计算这样一个半球空间内的积分,这显然是非常奢侈的。

这里BRDF可以看做是一个核函数,因为它是归一化的,这是基于物理的Microfacet BRDF模型能量守恒的特征,因此这个积分可以看做是对环境贴图的一次过滤操作。但是如果这个BRDF核函数本身是各向同性的,那么对于每个反射方向的这种过滤操作都是相同的,于是我们可以将这个BRDF函数在环境贴图上做一个卷积计算,形成一个预过滤(pre-filtering)的环境贴图,它相当于把这个过滤的积分计算提前到预处理阶段,这样在实时阶段,像素的着色计算就是对预过滤的环境贴图执行一次纹理查询而已。

而万幸的是,当前工业中使用的GGX模型正是各向同性的,或者它被普遍使用的原因正是因为源于预过滤等计算的需求。

预过滤是一种非常重要的实时渲染方法,它的优点是能够将积分计算简化为单次纹理读取操作,但是其缺点是仅能处理圆对称的核函数,否则我们需要更高维度的纹理来存储预过滤的数据结果。

如果我们将预过滤的思想从环境贴图中提取出来,我们就会推断,所有关于使用包含一个圆对称核函数的积分,都可以借鉴这种预过滤的思路。例如在前面介绍的VXGI中,在对体素进行采样时仍然会涉及到BRDF函数与体素中的光照分布的积分计算,如果使用各向同性的BRDF函数,这个积分计算仍然可以被转化为预积分,实际上这也是VXGI的思想之一。

而预过滤的另一个在实时渲染中的重要运用,可能被大多数人忽视,或者说没有意识到,那就是多级纹理(mimap)。为什么要使用多级纹理,那就是因为当采样尺寸远远大于物体表面的细节时,例如那些离摄像机比较远的表面,使用单个表面的采样点会导致走样,所以我们希望在这个范围内使用多个采样点来计算该区域的平均值,或者按照某个核函数对这些采样点执行加权平均,这实际上就是一个积分了,但是和上面的原因一样,我们仍然不可能在实时渲染去,去对每一个像素执行一个积分计算,考虑到这个加权的核函数一般是圆对称的,所以我们直接将该核函数与表面的纹理中的纹素执行预过滤操作,这就是多级纹理的原理和思路。

实时渲染中几乎一般以上的全局光照算法,基本上都涉及到预过滤的计算,因为它是实现简化积分计算的主要手段和工具,《全局光照技术》中有大量的篇幅介绍各种预过滤技术,例如阶层式预过滤,基于重要性采样的预过滤,以及一些能够实现实时计算的预过滤方法。

实时渲染的另一个重要的思路是投影近似,投影近似的概念可以使用传统的矢量投影的概念进行描述。考虑一个3D空间的矢量,它的各个分量x,y,z,如果现在我们考虑只有一个1D的空间,要想在这个1D空间内最找到一个对3D空间中矢量的最佳描述,我们可以怎么做呢,答案就是将这个3D的矢量投影到这个1D空间,为什么它是最佳近似呢,因为原始3D矢量和这个投影矢量之间的距离最近。

现在我们将这个投影的概念扩展到函数上,假设我们有一组互不相同的基函数,并且某个空间的任意一个函数都可以表述为这些基函数的一个线性组合,那么组基函数就构成了一个函数空间,有了这组基函数,我们就可以用一个由这些基函数的系数构成的矢量来描述任意一个函数。傅里叶变换就是基于这样的概念,其中那些正余弦函数就构成一组基函数,我们可以用这些正余弦函数的线性组合来描述任意一个函数。

如果我们将傅里叶变换的基函数的维度由单位圆上扩展单位球面上,这就形成了所谓的球谐函数,所以球谐函数的方法基本上和傅里叶变换的方法是一致的,因为他们本质上是相似的概念,只是基函数的维度不一样。

在傅里叶变换或球谐函数中,每个基函数都代表了函数的不同频率特征,理论上傅里叶基函数或球谐函数的维度是无限的,因此我们就需要无限个系数来表述一个函数。但是如果某个函数是低频的,例如间接光照,那么我们能否去掉高频部分的基函数部分,仅仅保留有限个基函数的系数来近似一个函数呢?答案显然是可以的!

实时渲染中有很多这有的处理,例如环境贴图在某些情况下也可以表述为低阶的球谐函数,特别是那些涉及到每像素计算时,或者每一帧需要处理多个方向分布函数时,函数投影近似就是一种非常重要且必要的手段,例如环境中可能需要在多个位置存储于位置有关的环境贴图,以向动态运动的物体提供间接光照,或者某些地方不能预计算,只能实时地执行积分计算,这时候更是需要使用更少量的系数来表述一个方向分布函数。

更多关于渲染中的数学知识可以参见本专栏的文章:渲染中的数学知识

更多关于渲染的概念,可以参见本专栏的文章:在《硬影像》与罗登导演聊渲染技术

以上只是简单介绍一些渲染中的一些重要方法的基本原理和概念,更多更详细的探讨,可以参见《全局光照技术》图书的内容。

我的学习方法建议

第一部分我已经说过,我的起点并不高,我甚至没有经过计算机科学的专业训练,我入行3D渲染领域也大概只有6年多的时间,跟你们中大多数的朋友一样,我也经历过在书海中苦苦求索的经历,我也曾希望寻求一些好的学习方法建议,好的参考资料推荐,我也是一点一点慢慢去摸索过来的,那么我是如何自学并到现在写出《全局光照技术》这本图书的呢?

我觉得计算机很多分支学科知识的学习会包括三个阶段:

  1. 学习编程语言及工具
  2. 大量编程实践
  3. 深入研究理论

计算机科学需要较好的编程基础及能力,考虑到它的基础地位,我会建议将编程能力的培养放到你所在学科的最前面。比如在第一个阶段,你只需要学习最简单的语言及相关开发工具,这个时候不需要将编程涉及到您的复杂专业知识中,你可以选择你所在行业中一些比较简单的示例用来辅助编程语言及工具的学习。

以我自己的经历,我在大学的时候开始自学ASP.NET,C#和Ruby on Rails,那个时候我还不知道怎样用ASP.NET去实现复杂的企业应用以及各种高端的架构知识,因此也就不会纠结于过于繁杂而导致选择迷茫,在这个阶段我就是使用ASP.NET和RoR做了一些简单的示例性的项目,这使我能够快速地入门一种语言和工具。当然的具体语言选择并不重要,编程的很多思想都是想通的。

是不是掌握了基本的编程能力就开始解决或者实现专业问题呢?我的答案是否定的,拿计算机图形学为例,很多算法和技术都是和对编程的理解有联系的,比如当我们在说针对硬件的优化的时候,你需要了解语言的指令怎样在处理器中被执行,变量如果由主存到缓存再到寄存器,最后被用于执行指令;比如当我们在讨论加速结构的时候,你需要了解这些结构为什么在内存中的访问是高效的等等。很多这些知识都可以在脱离特定复杂的领域问题背景下被学习,所以你应该首先具备非常扎实的编程能力,然后你在学习和处理领域问题的时候才会变得更加顺手。

怎样才能训练你的编程能力呢?答案当然是大量的实践,这个没有其他方法,你不可能靠看一本书来提高编程能力。这个没什么可说的,但是我想强调的时候,这种大量的编程实践不能寄希望于公司的项目开发,在软件工程中,公司的项目开发往往都会出于效率的考虑,公司会有大量的架构和编程实践及规范,你是在这些架构和规范下工作,这就像工厂里的一名流水人员,因此你所做的事情多半也是非常简单和重复性的事情,你在这样的背景下其编程能力的提升会非常慢和低效。

要想快速提升编程能力,你必须有一个自己的相对比较复杂的个人项目,或者说你在公司有机会从零去构建一个项目。自己的项目因为需要考虑方方面面的事情,你不但在锻炼软件工程的思维,你可以有更多编程实践的机会,并且你在实践过程中,各个细小的细节会扔给你非常多你不曾了解的问题,然后你需要去学习来解决这些问题,这个成长的非常会非常的快和高效。

比如我在毕业第一年的时候,那时候我想在Web浏览器中实现一个类似App Store的东西,于是我要了解怎么托管用户的App,怎样在app之间调度,我希望开发者能够基于Windows Azure来使用传统的流程开发app,于是我需要去学习Azure,然后发现Azure不能够分配太多账号,用户需要自己单独购买Azure非常麻烦,于是我深入分析Azure REST API的格式,实现了一个完全的反向代理服务器,它完全映射了当时Azure的30多个API,使得我可以将Azure虚拟成无数个账号供开发者使用。最后整个项目下来,我学习到了非常多的知识,并且编程能力得到大大提升,我的那个项目可以参考这里:艺街开放平台开源计划

最后,当你具备扎实的编程能力之后,你对专业领域知识的学习就会更加高效。在计算机领域,很多朋友都会很推崇阅读源代码的学习方法,我其实不太赞成,至少在图形学领域我觉得这种方法并不是最高效的,可能在传统的企业软件开发中,代码实现本身并不涉及太多专业的知识,唯有代码本身可能就是最好的解释。但是在图形学领域,图形学知识本身有比代码实现更复杂的理论,这些理论,有时候你听过阅读代码本身是很难理解的,所以最高效的方法应该是首先从理论着手,对理论的原理理解之后再去阅读代码实现。所以这也是我为什么强度编程能力在先的原因,因为你必须在阅读那些技术论文的时候,对其所涉及的关于实现部分的介绍,不要有任何理解上的障碍,否则这种障碍也会阻止你对理论的理解。

经常会有人问这样的问题:新手适合看什么书?有哪些书值得推荐的?《全局光照技术》适合萌新吗?需要什么基础才能阅读《全局光照技术》?

通常对于这种问题,我都不想去回答,或者说我其实真的不知道该怎么去回答,在我的心中,我确实对于图书没有很严格的质量划分,或者等级划分,除了大家都公认的那少数几本书,大多数对我来说都是一样的。

对于图书的选择,我有两个观点:首先是不要对一本图书寄予太多期望,只要一本图书能够真正帮助你解决某个比较大的困惑和理解,你就已经赚到了;其次,不要视图去给图书和自己定级,你唯一需要考虑的是“这本书是不是某个领域最好的书”?

对于第一个观点,同类图书之间通常都有很大的重合度,所以你不可能希望某本书的全部内容都是对你帮助巨大的;其次,一本书的作者通常都有不同的专注点和擅长的层面,每本书在某些方面都可能有着非常独到的解释和逻辑,但是在其它方面可能并不是很通俗易懂。所以针对这种情况,你有时候需要交叉阅读,哪怕是相同的内容,不同的图书可能给你不同的启发。所以当我在开始学习一种新的技术或概念的时候,我通常都会买几本同类图书,交叉阅读和理解,我基本上不会去区分哪些图书更好,只要能给我理解上带来帮助,我觉得就不错了,毕竟和知识相比,那个书价真的就是不值一提。

第二个观点是不要尝试给自己定级,给自己画一个圈圈!很多朋友会有很强烈的自觉性,很严格地把自己划分为初级中级和高级,当然这里面最多的是第一种情况,所以你看到整个世界都是萌新,我认为这是一种非常不利于成长的习惯。在我整个计算机知识自学的过程中,我几乎从来不会去思考说哪本书是适合新手或者说我这个级别的,我一般只会去询问哪本书是这个方面最好的参考资料。这里有两个原因,首先如果你将自己划到某个小圈圈里面,那么你就把自己与一些非常好的学习资料隔离起来;其次,对于一名图书作者来讲,他通常都不会去严格地把图书的内容分级,比如说完全针对高级开发者,这是因为知识的理解需要背景也需要连贯性,所以每本图书基本上都要从很基本的概念讲起,所以是除非是向论文这种完全不考虑读者背景而仅专注研究内容的介绍,几乎大部分图书都是适合所有读者的,或者说至少初学者也能从中收获不少知识的。那既然是这样,为什么不直接选择最好的资料呢,要知道这些图书的作者对知识的理解更加深刻,他们讨论的内容可能更加高级,但是他们对知识的逻辑理解可能会让你进步的更快。

更多关于我的学习心得,还是留到我的技术巡讲中吧?写这么多文字还是有点累哈!

诚挚邀请您来参加我的渲染技术巡讲活动

看了这些描述,你是不是有些心动了呢?《全局光照技术》不仅包含所有上述这些内容,还包含远远多于这些的深度内容!
更重要的是,我即将于2018年5-6月期间在全国举行一次线下的渲染技术巡讲,您将能够聆听到来自我亲身的技术讲述,这可能是国内目前为止在渲染方面最专业最全面的技术分享,如果您看了这些内容很感兴趣,就赶紧去瞧瞧吧!

渲染的秘密:《全局光照技术》线下技术巡讲暨众筹预订 – 摩点 – 文化创意众筹社区

祝您学习愉快!
秦春林

DXR对如VXGI之类的全局光照算法有多大的影响?

看到知乎上有关于DXR能否取代VXGI之类的全局光照算法,这里将其回答分享给观众号的朋友们。

首先DXR和VXGI并不是一类事物,其中算是一个框架,而后者是一个全局光照算法。如果非要比较的话,也许可以说成“以DXR所能实现的光线追踪算法在GI方面能够替代现在的VXGI算法吗?”,如果问题是这样,那答案就非常简单,那就是现在光线追踪算法远远不能做到实时。不过问题又来了,可DXR说它是“实时光线追踪”(real-time ray tracing)啊,所以这就导致了题主的困惑。

要解开这个困惑,我们从三个方面来阐述,首先是DXR的实时光线追踪到底是不是真的,如果不是真的,它到底包含了那些内容;其次是将现有DXR能实现的效果与VXGI进行比较;最后是如果DXR仅仅是一个光线追踪框架,VXGI能否集成进DXR中。

DXR实现了完全的实时光线追踪了吗?

这个答案毫不犹豫的是:No!

你在GDC上看到的所谓real-time ray-traced demo,实际上并不是整个渲染都是基于光线追踪的,整个渲染的大部分工作都还是传统的光栅化来完成的,DXR基本上只用来做反射,环境遮挡,和面积光源产生的软阴影等少数几项事情。为什么,因为一条光线的成本太高了,所以目前DXR能够实时完成的事情,基本上满足两个条件:一是每一帧处理的像素数量很低,例如目前实现的几种效果都是针对屏幕空间(screen space)的像素发射光线,也就是光栅化生成的可视图像所在的那些像素;二是每个像素只发射一条或者少数几条光线,例如反射只需要对屏幕空间的每个像素沿反射方向只发射一条反射光线,而AO和针对面积光源的Shadow rays也只需要少数几条光线即可。这样下来,整个场景每一帧也就是针对屏幕空间的每个像素发射少数几条光线而已,仅此而已,甚至两次以上反弹想都不用想。但即便这样,你都需要一个买不起的Volta。

另外也有一种情况,那就是完全使用光线追踪,而不包含光栅化,这种情况就是从摄像机向每个屏幕空间的像素所在的范围随机发射一条光线,然后根据BRDF随机选择一个方向,并且反弹控制在极少的数量,例如2,3次,这样下来每个屏幕空间的像素差不多也只有几条光线,整个过程都是基于蒙特卡洛方法的,由于光线数量非常少,所以最后的结果就需要严重依赖于降噪(denoising),文大他们展示的一些这些面的工作大概就是这个思路。这和上面的两个条件基本上也是吻合的,即只对屏幕空间的像素发射光线,并且每个像素只产生很少的几条光线?

那我们在激动什么呢?其实DXR并没有什么技术的革新,是NVidia在宣传显卡而已,在向你兜售未来,开玩笑的。我觉得DXR的意义就是将这种少数光线能做的事情开始引入到光线追踪算法中,这不仅仅是说我们迈出了第一步的事情,实际上它带来的画面提升也是非常大的,比如传统的光栅化只能处理点光源,即便是面积光源,也大都是被近似为一个“点光源”后按照阴影贴图的方式来做,但是使用DXR,面积光源完全按真实的物理方式去计算,这种效果的提升不仅仅是“画质”上的提升,它是由近似向物理正确上的提升,你看GDC上那些Demo,即便是简单的场景,使用DXR的面积光源要比光栅化的画面效果要好得多,因为整个场景更加接近自然。

但是,但是,但是,我们离完全的实时光线追踪是不是近了,毕竟我们迈出了第一步不是?

通常人类做一件事情,只要迈出第一步,第二,三……步通常很简单,最后99步可能非常困难,但是对于光线追踪来讲,第一步跟第二步的距离会非常漫长,毕竟光线一反弹起来就不可收拾。

现有的DXR GI与VXGI的比较

那当然也是不好比较了,DXR目前实现的主要是反射,AO和面积光源,VXGI实现的主要是间接光照,你让DXR去追踪一下间接光试试,估计10块Volta都不够!

当然它们都能处理AO,仅就针对AO而言,从效率上讲,VXGI肯定要快,毕竟它是对阶层式(hierarchical)的稀疏场景执行圆锥体追踪(cone tracing),而DXR是对整个几何场景的所有三角形网格执行光线追踪(ray tracing);但是从结果来讲,DXR绝对要好得多,因为Ray tracing本身是基于物理的,而VXGI的cone tracing是基于体积渲染积分模型的,它在光线步进的过程中,其遮挡关系是通过混合计算出来的,这跟透明度的处理原理类似,这种方式随着步进距离的增大,其误差也会增加增加,并且cone的半径过大也会导致误差。从下图就可以看出,观察点的发出的Cone上有两个物体各遮挡50%的光照,从实际上看观察点应该被完全遮挡而处于阴影当中,而实际上在VXGI中它的可见性为25%=50% x 50%。关于VXGI可以在《全局光照技术》中找到更多更详细的描述。

VXGI的Cone tracing使用的体积渲染模型

所以这也可以看到,目前实时渲染的方法,大都是近似,从这就可以看出上面所说的“由近似向物理正确”转变的意义所在。

VXGI可以集成进DXR中吗?

目前我们更愿意把DXR看做一个框架,而不是一种光线追踪算法,那新的问题是,VXGI可以集成进DXR吗,龚大的回答里也提到这个问题。据我所了解,不太容易,或者说效率很低。这主要有两个方面的原因。

DXR的光线追踪管线

首先是DXR所支持的基元类型的限制。DXR目前支持两种类型的基元类型,一种是三角形网格,一种是自定义的程序化基元(procedural geometry primitives),其中后者仅向DXR传输一个AABB的包围盒,然后具体的表面形状由application提供的一个intersection shader来实现,这个方面由于VXGI以体素的形式存在,显然只能选择后者。这个从表述上看问题不大,但是效率会有很大问题,首先是procedural primitives的性能本身并不如triangle primitive,其次是DXR是基于光线追踪,它会遍历所有体素结构,其光线与体素的相交顺序是不定的,因为DXR内部会针对光线与AABB包围盒的相交计算执行一定的调度,比如重新排序;而VXGI则是基于对阶层式结构的遍历,它依赖于由近向远或者说由前向后的步进顺序,这里直接就矛盾了,DXR并不保证这种顺序。

第二个问题更加严重,VXGI是基于光线步进(ray marching)算法的,这个步进的目的是为了能够根据步长来选择阶层式体素结构的分辨率层级,据我所知,DXR目前完全不提供ray marching的机制,它只有光线与几何体相交时才触发相关的shader调用。当然你可以说,如果我设置一个覆盖整个空间的几何体,然后在shader来做全部工作呢,那我说为什么不直接用compute shader呢,不然代码还要在DXR的管线里空跑一趟干什么呢?

以上关于VXGI的更多知识,《全局光照技术》中会有完整的一个章节的介绍;另外,关于DXR,我近期在发起一个全国的渲染技术线下巡讲活动,将在近几天开始报名,这个活动中会包含半个小时关于DXR的内容,敬请留意本公众号最近的动态。

More DETAILS! PBR的下一个发展在哪里?

最近几年图形学社区对PBR的关注非常高,也许是由于Disney以及一些游戏引擎大厂的助推,也许是因为它可以被轻松集成进实时渲染的游戏引擎当中,也许是因为许多人发现现在只需要调几个参数就能实现具有非常精细细节的表面着色了。反正现在知乎上随便一篇PBR的文章都可以引来大量的点赞,不管你有没有讲清楚,也不管我有没有看明白(当然没有调侃谁的意思啦,它们大部分都还不错,而且这篇文章跟他们大部分讨论的内容都不一样)。

那么PBR是否已经足够完美,如果不是,那么它有哪些方面的缺点及限制,以及针对这些不足,它的下一步发展应该是什么?这些问题就是本文会聚焦的内容。对于一个知识点,解释它的基本思路和概念也许并不是最难的,最难的是你知道它的限制和不足在哪里,这部分的理解往往会比它的基本概念要困难一些,你必须更深刻地理解这种知识才能洞悉它的缺点,然后你便清楚它的下一步发展应该是什么。因此,本文其实不仅会讨论PBR的下一步发展,这里对PBR不足的一些分析也许能够让你更深刻地理解它的概念。不信?往下读一读试试!

本文主要分为三个部分,第一部分简要介绍PBR的基本概念,第二部分则分析PBR存在的问题,然后我们结合一些研究成果探讨PBR的下一步发展。

PBR基本概念

这里,我们从两个方面介绍PBR的基本概念:首先介绍它处于渲染中的什么流程或者说哪个环节,或者说它在整个渲染中具有什么样的作用;然后介绍它的基本原理和思路。在图形渲染中,如果架构抽象的比较好的,我们可以将整个渲染流程划分为四个相对比较独立的部分:

  • 光源表述(lighting):例如是点光源,面积光源或者其它形式的(例如将网格用作一个)光源,是使用辐射强度还是直接使用辐射亮度来表述光源发出的光照。
  • 光照传输(light transport):就是光在场景中是怎么传输的,例如离线渲染中的光线追踪算法,它能模拟比较真实的光子传输行为,就是说能覆盖全部光子传输路径(或空间),但是在实时渲染中使用的一些近似方法也是表述光照传输的,虽然它可能省略掉了一些不重要的路径,但是这仍然是一种光照传输算法。光栅化的整个过程也是模拟了直接光照的传输。
  • 着色模型(shading):就是光与表面相交时发生的光学交互,比如反射和折射等,所有着色相关的数据汇总成一个材质对象,每个物体表面都需要一个材质对象,以便决定光在经过物体表面时应该如何对物体表面进行着色。
  • 摄像机模型(camera):比如投影方式,对景深效果的实现方式,是否支持全景绘制,是否支持对时间采样实现运动模糊等。

其中,光源表述和摄像机模型是相对比较简单的,最耗时间的是光照传输,因为它要执行光线与场景的相交计算,复杂的着色模型也可能比较耗时,但着色模型的最重要作用是决定物体表面所能表述细节(details)的能力。

在术语上,PBR英文全称为Physically based rendering,它是指能够实现接近物理真实的整个渲染算法或过程。但是由于光照的传输算法通常是固定且内置于渲染引擎的(或者说已经具有比较稳定成熟的算法,例如离线渲染领域的路径追踪算法,或者实时渲染领域里的光栅化+其它全局光照算法),剩下对基于物理的渲染算法影响最大的其实是表面的着色(材质)模型。因此,人们通常在讨论或描述PBR时,更多的是指其使用的着色模型。基于物理的着色模型更准确的称呼应该是Physically based shading,但是通常并没有PBS的称谓。

那么物理材质是指什么,“材质”其实就是光在与某个特定表面交互时需要的所有光学交互计算的数据,例如法线,纹理,BRDF等,也就是说,材质定义了最终表面接受光照后的视觉结果。对于物体表面视觉特征的定义,根据尺寸粒度可以划分为三级:

  • 基于网格顶点的表述,这种就是只对网格顶点的着色进行描述,然后中间的表面像素则通过插值来计算。
  • 基于像素的纹理贴图,这就是最常见的各种贴图,它们能表述像素级别的视觉特征。
  • 基于微观粒子的微面元表述,这就是我们这里所关心的物理着色。

上述前两种视觉表述是比较常见的,也是早期使用的一些技术。然而这两种表述远远不能描述物体表面的视觉特征,这是因为一个像素的尺寸远远大于物体表面上微观粒子的尺寸,如下图所示,图像空间中间的黄色方块表示一个像素,下面灰色褶皱部分则是该像素对应的实际微观结构,而光实际上是作用在这些微观结构上的,所以基于像素的着色模型(如直接贴图)反应不出真实物体表面的微观细节,所以这些技术都可以称为不是基于物理的材质。

物体表面微观结构的尺度远远小于一个像素的尺度

那么,要怎么表述这么微小的微观结构的光学交互行为呢?显然我们不可能像纹理那样对每个微观粒子使用一个纹素进行表述,那样我们的计算机内存将远远不够存储这种级别的纹理,所以人们提出了Microfacet BRDF理论,它使用一个法线概率分布函数,来模拟微观粒子的法线分布特征,这样就能够表述物体表面的微观特征,从而接近物理真实,所以称为基于物理的材质表述。

Microfacet BRDF表现出来的视觉特征是什么呢?那就是对于每个固定方向的入射光,我们可以有多个对该入射光的观察方向;或者反过来说,对于某个固定的观察方向,我们可以从一个像素观察到来自多个方向的入射光照。如果没有Microfacet BRDF,一个像素只被当做一个平面,对于固定的观察/入射方向,它只对应一个入射/观察方向。在Microfacet BRDF中,我们所能观察入射方向的方向范围,被参数化为一个粗糙度参数,如下图所示。这种着色模型使得我们能够表现比像素更小尺寸的表面细节。

反射光的范围大小取决于物体表面的粗糙度,物体表面越粗糙,它越能接收更大范围的光照

在渲染中,我们有许多模型来近似真实物体的微观法线分布,例如Normalized Blinn-Phong,Beckmann,GGX模型等等,这些模型具有不同的近似度和计算复杂度。由于这些模型都是对真实物理特征的近似,因此它们很可能不会遵循真实的物理分布,因此正性(positivity),互换性(reciprocity)以及能量守恒(energy conservation)被用来衡量一个BRDF模型是否是基于物理真实的,注意它们不是BRDF的属性哦,而是对BRDF是否满足物理真实的要求,因为你根据一些测量数据提出一个近似的BRDF模型很可能不是物理真实的,这些条件只是用来检验BRDF模型的物理真实性。

© DreamWorks Animation 2017.

顶点和像素级别的纹理可以存储在一张纹理图片中,这种基于物理的材质表述怎么存储呢?前面已经说过这个级别的表述是无法精确定义和存储的,所以我们将这个概率密度分布直接写进shader中,因为shader也是材质的一部分。

这也是为什么近几年实时渲染的游戏品质有了很大提升,实时渲染与离线渲染的最大不同在于光照的传输过程,实时渲染省略或者近似了很多路径,但是在光与表面的交互上,它只涉及一个公式的计算,并不会对性能造成太大影响,所以可以很容易地集成进来。不过实践中,实时渲染使用的概率密度分布函数要比影视中使用的计算量要简单一些,这只是在质量上稍有差异,但是不影响它表述微观粒子视觉特征的能力。

PBR的限制

有了上述Microfacet BRDF理论,物理着色的世界是否就完美了呢?换句话说你是否就能够通过几个神奇的参数表述任意细节的物理材质呢?

如果你仔细观察通过上述那些Microfacet BRDF模型渲染出的图像,你会发现虽然它们能够表述粗糙度,但是它们都太过平滑或者说模糊,例如下边右边的图。

右图:传统的Microfacet BRDF模型太过于平滑(图片来自【10】)

传统的Microfacet BRDF模型渲染不出上图中左图那种划痕的效果。这是为什么,这是因为出于计算效率,传统的Microfacet BRDF模型都是对真实BRDF分布的一个粗略近似,这些近似往往都非常平滑,如下图所示,右图表示一个比较真实的BRDF分布,而左图表示一个传统的Microfacet BRDF模型,左图可以看做是对右图的一个(非常)平滑的结果,这是因为我们需要计算效率足够高的着色计算,复杂的BRDF分布会大大增加采样的计算时间。这种平滑的结果使得传统的Microfacet BRDF模型只能渲染出一定距离范围之外的表面着色,你可以理解为距离越远着色越模糊,当然这里实际上不是指实际物体离摄像机的距离,而是说这种模型永远只能渲染出类似于超出这个距离的表面粗糙度,即使拉近摄像机的距离,它们看起来仍然是很平滑的,因为它们所使用的BRDF已经被严重的平滑了,也就是上面右图中的效果,那些更细微的细节被下面左图这样类似的BRDF分布给平滑掉了。

左:传统的Microfacet BRDF模型:右:真实的BRDF分布(图片来自【5】)

所以这里可以总结出传统的Microfacet BRDF模型具有哪些不足。首先,传统的Microfacet BRDF太过平滑,不能表现小于一个像素的几何级的细节,这些细节的尺寸介于像素和微观粒子之间,如文章封面左图中的划痕,后面会分析更多例子。

其次,物理材质的着色计算“表述”在像素着色器(shader)中,而物体表面的宏观结构往往通过网格顶点或者像素级别的法线贴图来表述,这两种几何表述是分离的,并且随着表面离摄像机距离的改变,一个像素的尺寸和一个纹理中的纹素的尺寸之间的相对关系发生着变化,当物体表面离摄像机足够远时,实际上物体的宏观法线贴图或几何结构其实变成了该像素的“微观结构”,然而,通常法线贴图或几何结构与BRDF都是独立的,例如法线贴图首先被过滤到最模糊的级别,然后用于Microfacet BRDF的计算,这就使得artifacts非常严重,例如下图中三种不同的距离下,近处的水波细节在远距离下产生较大的artifacts。

或者如下图中,光盘上的划痕,在远距离下直接被模糊掉了。

在远距离下,由于几何级的法线数据首先被过滤,然后作用与BRDF,因此这种细节丢失,物体表面的细节随着距离摄像机的距离改变而改变(图片来自【13】)

PBR的下一步发展在哪里?

上述的描述其实可以总结为两个方面:

  • 传统Microfacet BRDF对微观结构的表述精确度不足
  • 传统的Microfacet BRDF与宏观的(如法线)贴图或几何结构不相容,或者说不能相互协调工作

这是两个独立的问题,例如单提高BRDF的精确度不能解决第二个问题,因为对于远处的物体,我们需要将几何级的结构视作像素的微观结构(例如微面元),否则我们需要很高的采样才能消除artifact,而这对于远处的物体较高的采样显然是比较浪费的;其次,让宏观的几何结构与BRDF相协调对于近处物体的细节表述是没有什么意义的。当然如下所述,如果高分辨率的法线贴图被视作几何结构,那么第二个问题的确能改善第一个问题。

首先,对于微观结构的表述,出于计算效率的考虑,目前我们还不可能使用非常复杂的Microfacet BRDF近似模型,因为比较精确的模型可能需要上百倍的计算时间。当前的研究主要是集中于使用高分辨率的法线贴图(或者其它一些特殊的高分辨率几何结构)来表述这种介于像素和微观粒子之间的几何结构,然后将每个像素对应的这种几何级的数据与BRDF相融合,得出一种能够适应这些几何结构的Microfacet BRDF模型。这种模型能够表述更微观的几何细节,例如下图所示,光盘和地板上那种细节在传统的BRDF上是表现不出来的,因为它们会完全被平滑掉。

Microfacet BRDF与高分辨率贴图结合产生更多细节(图片来自【10】)

通过结合传统的Microfacet BRDF模型与贴图,两种着色技术被结合起来,使得我们不必使用更复杂的Microfacet BRDF模型就可以表述更精细的微观结构。

除了将高分辨率的贴图融入进Microfacet BRDF模型中,对于远处的表面,我们还需要能够直接将宏观的表面几何结构融入进Microfacet BRDF模型中,即这些宏观几何结构成为一个像素中的微面元本身。

在传统的Microfacet BRDF模型中,针对每一个像素,我们首先根据法线贴图或其它方式得到一个当前像素的法线,然后代入进Microfacet BRDF模型中计算出射光照。然而我们说过,Microfacet BRDF模型发生于像素尺寸,而法线采样发生于纹理尺寸,这两个尺寸通常是不对等且随着表面到摄像机的距离变化而变化的,例如对于比较近的表面,假如像素与纹理尺寸是一比一的,那么这个法线采样会比较准确,它可以直接被用于Microfacet BRDF模型中进行计算;然后对于远处的表面,一个像素尺寸可能等于多个纹素尺寸,这时对法线贴图的直接采用就会导致比较大的方差,我们需要花很多的样本才能把这些方差平均下来,因此传统的做法就是首先对法线贴图进行过滤,也就是从一个Mipmap中得到对应距离的法线值。这种做法虽然使用平滑的偏差带来了方差的减小,但是它又平滑了这种几何级的细节,所以我们仍然需要非常高的采样率来填补这些细节。

所以,如果我们能够将几何级的宏观结构也融入到Microfacet BRDF中,对于远距离的表面,宏观的几何结构直接集成于Microfacet BRDF中,就能够使用比较少的样本来得到远处表面的细节,例如下图中,使用传统的Microfacet BRDF,左图使用100个样本可以得到比较精细的细节,但是中图使用一个样本则比较模糊,因为较远的地方法线贴图的采样被过滤了,右图将几何结构融入Microfacet BRDF中,可以使用较少的样本得到远处的几何细节。

左图:传统的Microfacet BRDF,使用每像素100个样本;中图:传统的Microfacet BRDF,每像素一个样本;右图:将几何结构融入Microfacet BRDF中,每像素一个样本(图片来自【4】)

能够将几何级的贴图数据和Microfacet BRDF融合,许多的表面都可以得到更精细的表述。

图片来自【13】

当然,由于bump map或normal map都是对法线的fake,它们并不改变物体表面的几何结构,仅仅是直接给着色器传递一个假的的法线值,这个法线值可能导致物体表面的表面几何分布并不是一致的(consistent),因此这就破话了Microfacet BRDF的对称性和能量守恒。例如下图所示,由于表面的真实几何结构没有发生变化,然而着色使用了一个假的法线,因此使得一部分的方向被丢失,例如对于下图而言,左边半球与几何平面交叉的部分(红色箭头所示)和右图半球面下方的方向(红色箭头所示)都是不能被采样的,这造成了光照的泄露和丢失。

图片来自【11】

因此,开发更高效的Microfacet BRDF模型,使其能够与在bump/normal map的配合下能够呈现更真实的着色,也是Microfacet BRDF发展的话题,以下是Unity labs的一种解决方案。

图片来自【11】

总结

出于性能考虑,当前传统的Microfacet BRDF都采用比较模糊近似模型,这使得介于像素和微观粒子之间的微观结构被忽略。而实践上我们也不可能采用表述更精确的Microfacet BRDF模型,因为这往往需要较大的数据存储(例如一些基于数据驱动的Microfacet BRDF模型)或者较大的计算时间,不过实际上可能人眼也不可能分辨太过微观的细节,因此结合传统的(bump/Displacement/normal map等)贴图技术,通过高分辨率的贴图来展现比像素更微观的细节,并让这些贴图所表述的相对宏观的几何结构融入到Microfacet BRDF模型中,便成为比较简洁而有效的方法。此外,除了贴图级别的宏观几何结构,远处更大尺寸的如顶点级别的几何结构也是需要与Microfacet BRDF模型进行融合的。

对于理解Microfacet BRDF模型,表面表述的尺寸是一个非常关键的因素,仔细去理解每种尺寸下着色模型的选择,以及它们之间怎么联合起来对总的表面进行着色,这是让你透彻理解着色的关键。

一如既往地,上述这些内容会在《全局光照技术》中更详细地讨论,本书已经在摩点网开启正式预定,欢迎前去参观!

预定地址:《全局光照技术》出版在即!揭秘工业中最前沿的渲染技术-发现项目-摩点会想

参考引用或相关补充资源:
[1] 2010 LEAN Mapping
[2] 2013 Linear Efficient Antialiased Displacement and Re ectance Mapping
[3] 2014 Discrete Stochastic Microfacet Models
[4] 2014 Geometry into Shading
[5] 2014 Rendering Glints on High-resolution Normal-mapped Specular Surfaces
[6] 2014 Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs
[7] 2015 Multiple-Scattering Microfacet BSDFs with the Smith Model
[8] 2015 Skin Microstructure Deformation with Displacement Map Convolution
[9] 2016 Multi-Scale Rendering of Scratched Materials using a Structured SV-BRDF Model
[10] 2016 Position-Normal Distributions for Efficient Rendering of Specular Microstructure
[11] 2017 Microfacet-based Normal Mapping for Robust Monte Carlo Path Tracing
[12] 2017 Pixar’s Foundation for Materials
[13] Racing for Realism

 

在《硬影像》与罗登导演聊渲染技术

这周末,我参与录制了罗登导演(知乎: @Nordenbox)主持的《硬影像》播客节目,《硬影像》由 IPN 出品,由罗登主持,是一个关注影像之一切的播客。谈论影像背后的技术,历史和哲理。我们用比较通俗的方式讨论了渲染相关的许多话题和内容,大家可以访问以下链接进行收听。

收听地址:http://hardimage.pro/56

另外,由于实际说话的时候可能由于紧张,口误等原因,口述的内容可能没有文字的构句那么严谨,这里我也提供一个整理的文字版本,其中大部分内容是跟谈话内容相关的,但是注意这里不是访谈的文字版本,而是重新的描述。此外,这里可能并没有包含访谈的全部内容,而文字版本也可能稍微加了一点其它的内容。

什么是渲染?

渲染主要是指将一个用数字的方式描述的场景,转化为一副可视数字图像的过程。生成一副数字图像包括许多程序和步骤,例如物体的建模,场景的设置,游戏和影视中还包括物理模拟,动画控制,AI等等,其中渲染处于整个流程的最后一步,当前面所有流程结束之后,我们得到一个静态的场景描述,例如每个物体的3D位置,模型数据,贴图,摄像机位置和角度,光源设置等,然后渲染器执行渲染的过程将其生成一副2D的由像素组成的数字图像。由此也可以看出,渲染的流程相对比较独立于其它数字内容的制作流程,我们甚至可以很容易地针对不同(例如时间)需求对同样的场景使用或切换不同的渲染算法或渲染器。

形象的说就是,当每一时刻演员的动作完成之后,并且摄影师的镜头位置和方向确定后,摄像机要得到当前时刻整个可视场景的图像信息的过程。这个过程其实就是光照从光源发出,经过与场景的各个物体的反射或折射之后进入摄像机的传输过程,在术语上,渲染和光照传输其实就是等同的概念。当然这个例子有一点区别就是摄影的过程其实不是一个特定“时刻”而是一小段时间内接收光子的过程,也就是曝光时间,所以真实摄像机可以通过调节曝光时间来捕捉一些运动特征,如运动模糊(motion blur),然后数字摄像机则只能针对特定时刻进行计算,所以对于这种运动特征通常需要特别的方式来处理,例如在实时渲染中通过跟踪一个运动矢量(motion vector)来计算运动模糊效果,当然在离线渲染中我可以将光照传输函数加入进一个时间的维度,使得每个路径样本同时包含对时间的采样,来实现对所谓曝光时间参数的模拟。

渲染中最重要的技术要点是什么?

要回答这个问题,我们需要首先了解渲染器是怎样解决或者说计算上述的光照传输过程,传统解决光照传输最经典的方法是光线追踪,理解了光线追踪的思路,我们就可以很自然地看到光照传输的困难,进而明白渲染中最主要的一些技术要点。

首先什么是光线追踪?

为了在数字计算机中模拟光照传输,我们需要从光学中了解光的一些特征。我们看到的物体表面上每一个点的颜色,是来自于这个点所在的平面上空整个半球180度范围所有方向的光照的结果,因此当我们需要计算最终图像上特定一个像素的颜色时,它的过程类似这样:首先从摄像机沿这个像素的方向发射一条光线,然后光线会在半球空间发散成无数的光线,这些每条光线在空气中沿直线传播,直到遇到另一个物体时发生上述相似的发散过程,最后直到光线击中一个发光体而终止。同样的光照传输过程也可以反过来从光源向摄像机方向进行描述。

这个过程就称为光线追踪,其中每个由光源到摄像机(或者由摄像机到光源)的过程中所有直线的光线段连接起来就构成一条路径。因此为了模拟光照传输,显然每一个静态帧都需要产生大量的光线,这些光线的数量理论上是无穷的,实践中复杂的场景起码都是亿级别的。

那么实际上在程序算法上怎样解决这个问题呢?

在数学上,上述的光线追踪过程实际上是个高维积分,很难求解,一般使用的是称为蒙特卡洛(Monte Carlo method)的近似方法,该方法就是针对一定的概率密度函数每次产生一个随机的路径,这称为路径采样,然后计算这条路径的光照贡献值,最后把所有路径平均起来就得到每个像素的颜色值。这样的方法也称为路径追踪(Path tracing)。光线追踪算法的困难点其实有很多,例如焦散效果,体积渲染,间接漫反射光照等,以下挑选几个比较显著的。

首先是噪点比较严重

由于这些路径是随机产生的,因此有些路径产生的几率非常小,这就会导致比较大的噪点,所谓噪点就是由于这种随机性使得某些区域在早期得到更多的样本而使得这些区域内的颜色值过大,表现为那种比较白的亮点。在数学中,大数定律是能够保证在无穷的样本数量下,这些噪点最终是可以被完全消除的,但是这样的计算量和计算时间也是非常昂贵的;改善采样方法是可以减少噪点,所以当前离线渲染很多努力都是在开发一些更有效的采样方法,例如双向路径追踪,梅特波利斯算法,光子映射等。

光线追踪算法对处理器架构不友好

现代处理器使用的是一种多级缓存的架构,这些缓存的分级是根据访问速度来划分的,越快的缓存成本越昂贵,所以其容量非比较小,例如在一般的架构中,最靠近处理器的一级缓存,它的读取速度大约为1-3个时钟周期,但是其大小只有如32KB;二级缓存可以达到2MB,但是其读取速度却需要30个时钟周期,然后主存可以达到8GB,其读取速度为220多个时钟周期。这就好比说你在书桌上处理一件事情,你可能需要查询一些数据,让后你会在书桌上放一本或几本相关图书,需要的时候随时比较快的翻阅,但是可能有时候这几本书的内容是不够的,所以你需要起身到书房内的书架上查找另一些书籍,这就需要更多的时间,因为你需要起身行走的时间;然后如果你家里没有,你不得不去图书馆查询,这就需要更多时间;这里的书桌,书架和图书馆就好比一二三级缓存结构,书桌旁的书获取很快,但是只能放几本书,而图书馆的容量很大,但是需要花很多时间获取。而且除了容量,你每次携带的图书数量也是有限的,这称为带宽(bandwidth),也就是你每个时间只能携带多少数据。


因此,鉴于这种情况,理想的算法是,你的每个处理只涉及到同一本书,直到处理完同一本书才会需要其它书,也就是对书的需求不会出现交叉的情况。而缓存的情况也会自动获取相邻的内容数据,你在使用一级缓存的时候,二级缓存就会自动把这些数据附近的数据读取进来,这称为预取(pre-fetching)技术,如果你的数据访问是连续的,那么理论上你不需要更多时间等待。

然而在光线追踪中,光线在场景中随机穿行,因此对场景数据的访问完全是随机的,比如每次从内存中读取进来一个模型数据,可能只做一条光线的访问就没用了,然后下一条光线有需要访问另外的数据,这样整个场景的数据的大部分时间都停留在“运输”上,处理器大量时间处于等待状态。因此迪士尼自家渲染器Hyperion的最大特点就是对光线在执行相交计算之前按方向进行排序,这样使得每一束光线尽可能与相邻的物体相交,这些一次读取进缓存的数据可以被充分利用,减少运输成本。

什么是全局光照?

其实这是一个更主要是针对实时渲染的名词,由于离线的光线追踪算法的成本很高,所以实时渲染通常不计算完整的路径,而是只直接计算所谓的直接光照(direct lighting),即光线从光源出发,经过与场景中表面的一次交互之后,然后就进入摄像机,即是只计算摄像机直接能够看到的那些表面的光照,这样的直接光照能够被GPU的光栅化技术快速处理,实际上现代图形处理器最早就是为了加速对直接光照的处理而诞生,光栅化主要是对全部物体遍历一次,然后对每个点执行一次光照计算,其实也就是循环所有光源,看这个点能不能被光照照射,即有没有被其它物体遮挡,有照射则直接计算反射光照,没有就忽略。这样的直接光照又称为局部光照(local Illumination)。早期的游戏都是只有直接光照的,然而这样的光照结果显然不能满足要求,所以才引出全局光照(Global Illumination)这个名词,简称GI,由于多次反弹的光照计算成本很高,因此GI的实现很复杂,通常都是使用一些近似技术,我们后面再讨论。而对于离线渲染,它本身主要都是考虑完整路径的光照的,所以离线渲染中的光照传输其实天生就是全局光照。当然,早期的离线渲染器由于当期处理器的限制,其实算法跟现在的实时渲染差不多,所以在早期的离线渲染器中也有这样的区分。

什么是RenderMan RIS?

这是一个完全基于路径追踪的新版本,以取代基于Reyes的旧版本,Reyes是一种非常古老的近似方法,它还要起源于1987年Robert Cook提出的Reyes算法,它使用类似现代实时渲染的一些方法进行渲染,它不是基于物理的渲染,并且流程比较复杂,比如不同的效果需要使用不同的shader来实现,美术需要控制很多渲染相关的参数,修改起来非常麻烦,渲染器的修改往往需要美术人员学习新的技术。但是Reyes的架构还是非常稳健,高效的,所以直到去年的《魔兽世界》都还是使用基于Reyes的RenderMan版本。

也正是由于Reyes的稳健和高效,使Pixar放慢了对基于物理的更真实和高质量的路径追踪算法的开发和使用。基于路径追踪的渲染算法最早在1998年已经被蓝天工作室(Blue Sky Studios)使用于制作了短片《Bunny》,好像内地时光网上翻译为《棕兔夫人》,然后于2006年被用于制作第一步动画长片《怪兽屋》(Monster House),渲染器是Arnold。

使用RIS的流程则会更加简单,可以更集中于内容创作,编辑期的预览反馈更真实和实时。Pixar自家的《Finding Dory》及其后续Pixar自家电影都使用RIS,第三方电影更慢一些,例如《Tomorrowland》,《Doctor Strange》等都是基于Reyes的版本,《Warcraft》是工业光魔最后一部使用Reyes渲染的电影,《Rogue One》则是第一部工业光魔开始使用RIS版本的电影。RenderMan RIS比迪士尼自家的Hyperion都还晚,Hyperion的第一部电影是2014年的《超能陆战队》。

这是不是意味着RenderMan已经落于后于其它较早拥抱路径追踪的商业渲染器了?

这个问题当然不能简单地以拥抱路径追踪算法的早晚来定论,这是外行人的观点。我们以下从两个方面来说明,一个是RenderMan的技术架构,当然后面我们还会举例一些技术进行分析,其二是Pixar的技术团队的实力。

RenderMan RIS的技术架构

首先一句话描述,RenderMan RIS使用的几乎是目前世界上基于路径追踪渲染算法的最好的渲染器架构。路径追踪算法只是一种基本思路,实际每个渲染器的实现差异是非常大的,涉及的内容也非常多,很多渲染器都会针对自己已有的一些制作经验和流程对其中的某些部分进行特别优化,例如很多渲染器会将一些并行性比较高的计算转移到GPU去执行,或者对某些效果进行特别处理,例如将头发,布料,体积渲染,次表面散射等交给特别的渲染通道去执行,这些渲染通道可以使用一些(可能不是完全基于路径追踪的)近似方法。

上述这些改进和优化表面上看起来提高了渲染器的效率,然而却损害了路径追踪算法的整体架构,因为很多发表的论文都是针对一个特定的方面,而且大多都是在某种程度上的近似,这些方法跟路径追踪的思路反而是相悖的,因为路径追踪算法其实是一种很暴力(brute force)的方法,它保证最高的质量,但是却抵制近似,因此如果一个渲染器要加入某种近似,一定是需要对渲染器相应的方面进行特殊处理或对路径采样方法做出一些限制,例如Hyperion的光线排序虽然很厉害,但是它基本上只适用于单向路径追踪算法,而不能使用更高效的双向路径追踪算法以及其它更高级的如梅特波利斯算法,光子映射等,当然它们总是可以对渲染器进行修改以适应新的算法,但问题是这种改动量往往是非常大的,每次添加一个新功能都需要修改很多地方,甚至对美术制作流程做出影响。

RenderMan是怎样处理这个问题的呢?RenderMan更重视渲染器的底层系统架构,而将渲染器性能的优先级置于系统架构之后,RenderMan会很谨慎地随便加入一些上层局部的优化,它基本上只会考虑哪些最基础级别的重大的算法改进。它最初基于PBRT渲染器建立而来,PBRT是众所周知的非常好的路径追踪算法基本架构,拥有非常优秀和灵活的架构,它已经有十几年的历史,并且获得过2014年的奥斯卡科学与技术成就奖。RenderMan一直保持着这个基础架构,不会轻易加入影响这个架构的一些局部优化的内容,但是它在基础级别加入了最近几年比较重大的一些基础级别的新技术,例如VCM,UPBP(后面讨论)等,正是由于RenderMan维持比较稳固的基础架构,它才能以最小的改动成本加入这种基础级别的改进,反过来这种基础级别的算法改进对渲染器整体提升是非常重大的,而其它渲染器由于在上层做太多优化,使得要兼容新的基础算法不太容易,这不仅改动较大,可能影响整个美术制作流程,因此渲染器的发展反而会受到限制。

另一个方面是为什么RenderMan一直保持只使用CPU渲染,表面上看起来GPU能高效地做很多事情,但是其实路径追踪算法天然是对CPU更友好的,所谓的GPU渲染不过是需要花很多时间将渲染算法中可以并行的部分提取出来交给GPU处理的,但是这种提取工作非常繁琐,而且一旦基础算法改动,这些工作都要重来。当然RenderMan准备在22版本之后加入CPU+GPU的混合模式,称为XPU,这是因为现阶段基础算法发展已经比较完善了,这个时机开始做GPU的提取比较合

RenderMan的“技术团队”实力

放眼当今世界,在视效与动画领域,没有任何一家公司的研究实力能够超过迪士尼,迪士尼总共有5个比较主要的研究中心:皮克斯,工业光魔(ILM),迪士尼(瑞士)苏黎世(Zurich)研究中心,迪士尼动画以及卡耐基梅隆大学实验室。这五大研究中心的成果都是共享的,并且为了提高研究质量,这五个中心的研究工作甚至会交叉形成竞争,最后优胜出的技术被采用,而所有这些成果都是通过皮克斯的RenderMan这个出口进入到工业当中。所以可以看到几乎Hyperion具有的先进技术,都同时也被运用到RenderMan当中,例如发丝,布料,次表面散射,体积渲染等,同时由于前面说过RenderMan具有更稳健的基础架构,所以它甚至比Hyperion更容易采用最新具有重大意义的基础架构级别的成果,例如VCM技术,基于光束采样的UPBP体积渲染技术(后面会讨论)。

适应性采样

适应性采样在RenderMan中大量使用,例如一个1920 x 911 分辨率的静态帧有174 9210个像素,每个像素会发射上千条路径,传统的做法是对每个像素都发射固定数量的路径,然而根据图像的颜色分布不同,有些区域颜色变化比较小,因此随机路径出现的误差较小,这些区域可以使用更少的路径即可达到很好的效果,而另一些区域如物体的边缘或阴影边界,这些区域颜色变化比较大,随机数更容易产生更大的误差,因此可以对这些像素区域放置更多的路径样本,这种技术称为适应性采样(adaptive sampling),它能够根据图像分布自适应地调整每个区域路径样本的数量。

这样的适应性采样同样适用于巨量点光源场景中的光源选择,例如《寻梦环游记》电影当中的死亡之地(land of the dead)整个场景具有826 5557个点光源,也就是对于每条路径都需要遍历这800多万个光源,显然计算量非常高,如果我们在对光源的采样迭代过程中不断根据前面样本的误差分布对每个区域的采样分布进行适应性调整,即可以以比较少的光源样本选择达到比较好的光照结果。

降噪处理

对于路径追踪算法,当路径样本数量较少时,始终会有噪点,更多的路径样本数量可以减少噪点,增强图像的质量,但是这会花费更多的渲染时间,理论上需要无限的样本数量才能完全消除噪点。为了节省渲染时间,降噪技术(denoising)被引入渲染器中用于对使用较少路径样本渲染的图像结果进行降噪处理。降噪处理的思路类似而对图片进行滤镜处理,使图片变得更加平滑,但是离线渲染中的降噪还是要复杂得多,它使用的平滑的依据是局部区域内样本误差的大小,并根据误差分布来决定平滑的范围,其它一些像素信息如深度,法线等也被引入降噪技术以帮助更好地降噪。

降噪是近几年离线渲染领域的热点,也是光线追踪算法向实时渲染转换的关键技术之一,因为实时的光线追踪会使用更少的路径样本。

毛发渲染

毛发渲染是迪士尼和皮克斯的关键技术之一,2003年Marschner提出了渲染毛发的著名的Marschner模型,该模型将一根毛发描述为一个圆柱形的并在圆面上具有一定鳞片结构的线状结构,并描述了光在毛发内部的传播行为,遵循Marschner模型的毛发渲染能够呈现出比较真实的毛发效果,皮克斯在此基础上进一步发现使用椭圆形而不是圆截面的毛发丝更接近物理真实,因此提出改进的皮克斯Marschner毛发模型。

在Marschner模型中,一根毛发可以使用一个纹理当中的一条线段表述,该纹理被贴到一个曲面网格上,网格可以接受物理影响而使发丝跟随移动,而纹理上的每个线段只提供毛发的位置,它的尺寸和实际光照均由Marschner模型进行计算,该模型根据一个观察方向和入射光计算出毛发的真实光照颜色。

在很多渲染器中,毛发,次表面散射,布料等特殊效果都是使用独立于其它表面渲染的一个通道,也即是说在渲染完所有表面之后再对这些特殊效果使用单独的渲染流程进行特殊处理,这往往会使制作流程变得更加复杂,渲染算法架构也会更加复杂,而RenderMan现在可以将所有这些特殊效果融入到表面的着色计算当中,也就是说场景中所有渲染计算都是使用一个统一的路径追踪通道完成,这大大简化了制作流程,这也是得益于前面介绍的比较稳固的渲染架构。例如在渐进式的交互式阅览中,这些特殊效果能够跟其它表面渲染同步展现,而不需要等表面渲染完毕才开始渲染这些特殊效果,这大大节省了设计时间及提高了效率,在设计阶段预览的技术也称为live rendering。

体积渲染

体积渲染是RenderMan的另一个重要技术,所谓体积(Volume)是相对于表面(surface)的一个概念,比如在表面上光照只在每个表面位置处发射反射或折射,而在体积中,例如烟雾,云等环绕的环境中,由于空气中不再是真空,而是到处都充满着粒子,所以光在这样的环境传播时,会与分布于整个空间中的粒子发射碰撞而发射散射,因此体积中每个位置都需要计算光照交互,我们也称体积为参与介质(participate media),因为整个体积都是参与光照交互。

这样的计算量显然是非常大的,传统的方法就是对于一束穿过一个体积的光束,在该光束上执行光线步进(ray marching)算法,也就是随机选择该光束上的一些点执行光照计算,然后将所有采样点的光照累加起来,这样的技术也称为基于点采样(point sampling)的技术。

然而由于点采样满足不了体积内处处发生交互的这样一种连续的交互方式,所以渲染效果比较差,计算时需要使用大量密集的点采样,才能使光照效果看起来比较真实。于是,迪士尼苏黎世研究中心的Wojciech Jarosz(目前已经离开迪士尼任英国达特茅斯(Dartmouth)大学的助理教授)提出了具有革新意义的基于光束采样(beam sampling)的体积渲染技术,该技术使用一种特殊的方式直接计算体积中的一条光束(而不是一系列点)的光照,不仅大大提升了计算效率,而且提高了渲染质量,是离线渲染领域体积渲染的重要里程碑。

什么是实时渲染,它与离线渲染有哪些差别?

实时渲染是对渲染加了一个时间限制,即要求整个光照传输的过程在比如1/60秒之内完成,而在实时图像程序中,整个运行时的计算还要处理其它如动画,AI等其它工作,实际上留给渲染的时间更是只有几百毫秒。所以显然目前实时渲染不能使用上述离线渲染的光照传输方法,因为上述方法需要数分钟甚至数小时的时间来处理一帧的图像。

实时渲染算法与离线渲染算法的差异较大,主要表现为实时渲染通常将光照传输的过程分成两个方面,即直接光照和间接光照,直接光照是指光子从光源发射出后只与表面进行一次反弹即进入摄像机,而间接光照就是在所有需要经历2次及以上反弹的光照,后者又称为全局光照。

怎样计算直接光照,或者说渲染管线的基本流程

直接光照的处理通常是借用现代专用图形处理器(GPU)的光栅化流程来处理的,图形处理器的渲染管线循环遍历场景中的每个物体的每个顶点一次,并使用光栅化程序对这些顶点进行插值以计算表面上每个像素位置处的颜色,在计算每个像素的颜色时,我们直接计算来自光源的光照,即循环所有场景中的光源看是否每个光源对该像素形成光照,其可见性或者是否被遮挡由一个阴影贴图来判定,阴影贴图中存储的是每个光源所能看到的表面像素位置,它是通过向摄像机置于光源位置处,然后渲染一个全场景的图,并记录那些所有直接可见的表面像素位置。最后,像素之间的远近关系通过一个深度缓存来判断,深度缓存记录了当前已处理的图像上每个像素位置的深度值,在遍历后面的像素表面时,它将当前位置与深度缓存中已有的位置的深度值进行比较,如果当前位置更靠近摄像机,则丢掉深度缓存中之前存储的像素并用当前像素代替,同时存储当前像素的深度值至深度缓存中供后面比较使用。上述的流程是高度并行化的,得益于现代图形处理器的并行架构特征,所以能够被高效计算。

怎样计算间接光照,或者说常用的实时全局光照技术

间接光照的计算复杂度要远远高于直接光照,当前几乎没有任何方法能够实时完整的计算全部光照传输过程,所有方法都是基于一定的假设作出的一些近似处理。例如漫反射光照是与观察方向无关的,所以对于静态物体,其漫反射光照可以被预计算出来并存储在一个贴图中,然后在实时运行时就只有一个贴图操作而不需要执行光照计算;例如对于来自较远的环境的间接光照(如来自天空的光照),由于表面的位置相对于表面与这些环境的距离可以忽略不计,所以整个环境光只与方向相关,从而可以将整个环境的间接光照保存在一个环境贴图,在渲染的时候只需要计算出入射方向就可以从环境贴图中查询到一个光照值进行计算;对于动态物体,如人物角色,它的间接光照看起来无法预存,但是考虑到间接光照的变化频率是非常小的,所以我们可以在角色会经过的空间范围内存储一些比较稀疏的光照分布,类似于将间接光转换为一些“点”光源,然后当角色经过时可以使用附近的这些光源进行插值计算;几乎所有现代大型高质量游戏的渲染都涉及到很多这样的预处理计算。当然在实时渲染中还有很多对不同方面的一些近似方法。

现在实时渲染看起来非常逼真,那这样的实时渲染画质与离线渲染的差异到底在哪里?

上述的描述看起来实时渲染跟离线渲染的差异还是很大的,那为什么现代很多游戏的画质看起来感觉跟影视的画质差不多呢?其实我们之所以有这样的疑问,是因为我们的眼睛根本无法分辨精确的颜色,研究人眼识别周围环境光照的学科称为视觉感知(visual perception),所谓感知并不是一种精确度量,我们无法拥有对两个图像的真实差异进行分辨的能力,我们能分辨的误差具有一定的范围,例如人眼对于物体的边缘形状感知是非常明显的,如果没有阴影就没有立体的感觉,消除边缘部分的锯齿等措施就可以使眼睛的不适大大减小;例如对于任意一张图片,我们无法分辨这张图片中2%以下的误差,因此我们就可以忽略对这部分误差范围内计算。这些因素加上上述的一些高质量的预处理计算,所以我们会觉得一些实时渲染游戏作品的画质很高。

实时渲染有哪些应用场景?

现在人们开始越来越把目光投向实时渲染,例如很多动画短片都大量采用实时渲染来进行计算。另外,例如VR等应用场景对任意视角的渲染要求,也使得实时渲染的需求大大提升,可以预计实时渲染技术会对于很多需要对数字可视化的场景,例如医学成像,物理定律的可视化模拟,化学微观结构的可视化演示,军事化的模拟训练等等发挥较大的作用。

但是,目前实时渲染的结果只是对人眼是“正确的”,并不是对计算机是正确的,所以那些需要得到精密渲染结果而不是仅仅用于人眼观察的场景是不应该使用实时渲染技术的。

另外,在离线和实时的时间要求之间,还有一个交互式(interactive)的时间要求,例如很多3D软件中的需求,也就是在某种程序的编辑阶段,而不是最终的运行时阶段,我们可能不需要完全实时的程序,但是需要在几秒或者很短的时间内得到编辑结果的反馈,例如游戏和影视场景的编辑,在这种需求下,当前的实时渲染并不是一种很好的选择,因为他的最终结果需要依赖于大量时间的预计算;相反,基于光线追踪的技术,虽然得到最终高质量的渲染结果需要大量的时间,但是却可以在较短时间内使用少量的样本得到整个编辑的反馈,并且由于更多的时间花在后面对更小误差的处理上,实际上得到一个快速能够反馈编辑结果的时间是很快的,这方面一些离线渲染技术反而是更好的选择。

电影渲染是非实时渲染,以后会不会用到实时渲染中

毫无疑问,未来的实时渲染一定是光线追踪,这不仅是因为它的渲染结果是更物理真实的,还因为它简洁一致的光照传输模型,当前的实时渲染融入了太多繁杂的近似计算,这些近似处理并不是必须的,而是受限于硬件限制,但是这使得工程师要去了解非常多各种各样的近似技术。人类科技的发展是趋向于高度简洁和抽象化的,因为这也是人更易于理解的,光线追踪就符合这样的特征。

但另一方面,光线追踪的实时化并不仅仅是硬件发展的要求,路径采样基础算法架构的改进也是非常重要的,我们仍然还需要再算法层面做很多改进工作,甚至也有可能发现全新的光照算法。

怎么样,听/看完上述内容,是不是很想买一本《全局光照技术》来读一读呢?本书正在摩点网火爆众筹预购哦,已经超过12万的预定量,很多小伙伴已经在你前面踏上进军图形学的轨道上,此次众筹也是全宇宙最快最优先获取《全局光照技术》图书的途径,快去看看吧!

预购地址:https://zhongchou.modian.com/item/9055.html

https://www.fxguide.com/featured/pixar-deep-dive-on-sss-siggraph-preview/
https://renderman.pixar.com/news/presentations-renderman-art-and-science-fair-2017
https://www.fxguide.com/featured/rendermanris-and-the-start-of-next-25-years/
https://rmanwiki.pixar.com/display/REN/Sampling+Modes
https://rmanwiki.pixar.com/display/REN/PxrMarschnerHair
https://www.fxguide.com/featured/beam-rendering-extended-at-siggraph-2014/
Sorted Deferred Shading For Production Path Tracing
http://graphics.pixar.com/library/Reyes/
http://pbrt.org

渲染中的数学知识

《全局光照技术》的众筹过10万了,按照约定我将赠送每名众筹支持者一份学习路线图以及总结我的一些学习方法,而学习路线图的其中一项内容就是介绍图形学中的一些数学知识,所以这里先简要做个概述。

很显然,数学是理解3D渲染算法的重要基础,那么这是不是意味着你需要重新去复习整个大学工科数学的知识呢?实际上作为工程师,我们的目标只是要理解工业技术(而非背后的数学知识)的原理,这本也是工程技术和理论研究的区别。一门数学学科本身是需要去解决更一般的问题的,然而对于理解一种工程技术,如果你不需要去设计和改进算法本身,你往往只需要了解它的(可能是非常简化的)一部分或者说理解它的意义即可,当你对整个工程技术的架构比较熟悉之后,你可以从某个方面深入去学习,定制和甚至改进。

以下我从渲染方面做一些简要分析以及归类,列出一些大概需要掌握的相对比较重要的数学知识,并对每种知识做一个简要概述,以及说明每个知识点用于解决渲染中什么样的问题。

蒙特卡洛方法

蒙特卡洛方法是整个离线渲染最核心的基础,由于渲染方程是一个(理论上无限)高维积分,所以它不可能通过分析的方法求解。你需要深刻明白对一个概率密度函数进行抽样,并用所得样本来求解一个积分值的概念,我们称作对积分的一个估计,不仅仅是渲染方程,渲染中的很多积分计算可能都需要使用蒙特卡洛方法进行计算;在这个过程中由于随机数本身的方差属性,因此估计值也具有方差,减少估计的方差是渲染当中的核心内容,你需要明白每个样本参与估计的“贡献值”的概念,贡献值越小的样本越容易产生较大的方差,使每个样本的贡献值尽可能大,这个概率密度函数与被积函数需要尽可能的相似,这又称为重要性采样;然而我们很难找到与被积函数相似的概率密度函数,但是很容易找到与被积函数的部分相似的概率密度函数,因此我们希望将多个重要性采样组合起来,这就是复合重要性采样,你要明白复合重要性采样的核心是使来自每个重要性采样的样本的贡献值尽可能相似。除了数学层面,你还需要理解双向路径采样中顶点连接涉及的一个重要方面,那就是顶点连接不是一个随机的过程,因此这个它使得连接起来的路径具有独一无二的组合概率密度函数,因此对于同一长度的路径,在不同位置处进行连接是一种不同的采样技术,因此当你产生一条完整路径之后,实际上你(通过在不同位置处连接两条子路径)产生了多个采样的结果,然后你使用复合重要性采样对所有这些采样技术进行组合。

傅里叶分析

傅里叶分析可能是仅次于蒙特卡洛方法的数学工具,它广泛运用于过滤,平滑,以及数据压缩等方面,它也是小波分析和球谐函数的重要基础。如同一系列正交的坐标轴(如(0,0,1), (0,1,0), (1,0,0))构成一个矢量空间,然后该空间中的任何矢量都是这组正交基矢量的线性组合一样,如果一系列的函数是相互正交的(即它们每两个函数的乘积的积分值均为0,除非两个函数相同,此时积分值为1),则这些函数构成一个函数空间,因此该函数空间的任意一个函数都可以表述为这些基函数的线性组合,傅里叶变换使用的正余弦函数正是这样的一组无限个数量的基函数,因此这就是为什么任意函数都可以进行傅里叶变换,傅里叶变换的本质就是将一个函数转换为所有这些无限个正余弦函数的线性组合,这些线性组合的系数是由一个称为投影的方法计算的,该方法的算法就是通过求原始信号函数与某个基函数乘积的积分值,理论上我们记住这无数个线性组合的系数就可以重合合成为原始的信号函数,这个过程称为重建。所有这些投影形成的系数形成一个连续的函数,它反映的是原始信号函数的频率分布,如果你去掉该频率分布中的某些区间,你就丢掉了原始信号对应的频率部分,通常对于一个方差比较大的采样结果,我们可以丢弃掉频率高的部分,它们通常都是导致方差较大的罪魁祸首,因此函数的高频部分需要更多的样本,而由于计算资源限制我们通常都无法满足这样的条件。你会发现一个在频率域对频率分布进行带限的函数,在原始的时间域或空间域变成了一个平滑函数,这也是通过对这个带限函数本身进行傅里叶逆变换得到的,这就是过滤的思想。你还会发现在频率域计算两个函数的乘积变成了时间域或空间域对一个数组(例如所有像素组成的一个图像)元素中的每个元素都执行一次过滤计算,这就是卷积的概念。

小波分析

函数空间的投影和重建的概念也是小波分析的基础,小波函数是一类特殊的正交基函数,即低频率的基函数构成的函数空间是高频率基函数构成的函数空间的一个子集,这就使得高频部分的基函数系数可以表述为与低频部分基函数系数的差值,这种特性使得小波变换形成了一个多分辨率的结构,你可以想象对于多级纹理(mipmap),低分辨率的图像是高分辨率图像中相邻元素平滑过滤得到的,例如对于较远的表面,使用低分辨率的纹理就可以得到很好的近似,这种结构特性被天然使用到辐射度方法中,你会发现原来我们不需要对每两个细分曲面进行光照传输的计算,因为有些较远或者立体角较小的范围,这部分可以使用低分辨率的曲面细分网格结构,这称为阶层式曲面细分方法。

球谐函数

函数空间的投影和重建也是所谓球谐函数的基础,球谐函数本质上就是将傅里叶变换使用的单位圆上的正余弦函数扩展到单位球面上,这些基函数实际上就是将三维空间的勒让德多项式进过缩放是之恰好位于球面上,由于单位球面坐标上的长度固定为1,因此球面坐标系退化为一个二维的单位球面坐标系,其两个坐标值构成一个空间的方向,因此球谐函数的线性组合可以用来表述一个与位置无关的方向函数,而方向函数在渲染中太普遍了,例如环境贴图就是一个与位置无关的方向函数,表面的反射方程也是一个方向函数,它根据一个入射方向分布计算出一个出射方向分布,因此球谐函数可以用来表述光照传输函数和环境贴图光源,同样去掉高频的部分,使用少量的系数就可以近似一个方向函数的低频部分,这就是预计算辐射度方法的数学基础,此外球谐函数的一些特性,如旋转不变性,卷积,内积等,这些也是辐射照度缓存算法的基础。

几何光学

除了光滑平面上的反射/折射定理,光学部分最重要的内容是关于微观表面的光照传输。在数字场景表述中,我们可以使用纹理贴图来表述一个表面的属性,例如BRDF双向反射函数,折射率等,然而要知道实际物体的微观表面结构的尺寸是非常小的,它甚至比一个像素的尺寸还要小得多,这个时候用贴图是没有办法描述的。然而我们可以使用一个像素的表面“展开”成一个分布函数,注意,原始纹理像素表述中,每个像素只产生一个确定的值,入射对于一个固定的入射方向,始终会反射到一个固定的出射方向,但是现在对于一个像素,相同的入射方向可以根据概率被反射到不同的出射方向,其中每一个不同的交互结果模拟了一个微观粒子(可理解为一个微观平面)的行为,这就使得光照传输可以在像素级别处理微观粒子结构的交互,这就是著名的微面元理论,不同的微面元的方法就是建立不同的分布函数模型,它们主要是建立一个这些微观粒子的法线分布,同时还有建立这些粒子形成的不平整曲面见的遮挡等关系,最终将菲涅尔函数融入到分布函数中,形成了最终的微面元双向分布函数。

梅特波利斯算法

如果采样使用的概率密度函数与被积函数不相似,那么样本的贡献值就不是一个常数,这意味着某些样本更重要或者更不重要,这就是使得估计的方差比较大,我们需要调整概率密度函数。如果采样使用的概率密度函数完全正比于被积函数,则样本的贡献值为一个常数,估计的方差为0,并且这意味着每个样本的计算都不需要计算贡献值,我们只需要数每个区间样本的数量就可以得出被积函数(即最终图像)的分布。梅特波利斯算法正是通过一种取舍的机制使得采样的概率密度函数正比于被积函数。其原理来源于马尔可夫链,马尔可夫链是一种在稳定状态下,系统之间各个状态之间转移概率的分布,梅特波利斯算法将整个被积函数的分布当做一个马尔可夫链,然后通过定义一个状态之间的转移概率分布使整个状态之间的分布相似于被积函数。由于梅特波利斯算法能够产生完全相似于被积函数的样本,因此可以很轻易地找到一些特别困难的路径,是离线渲染当中一种非常重要的采样方法。

模拟退火/总体蒙特卡洛方法

传统的梅特波利斯算法并没有说明样本的产生方法,在光线追踪中一般是使用传统的如双向路径追踪来产生一个样本路径,然而对于同一路径,双向路径追踪可以使用多种采样技术采样而得,得到一条贡献值较大的路径的概率取决于其使用的采样技术,在原始的MLT或PSSMLT算法中,每种采样路径是随机选择的,然而除了可以对路径的几何信息(如位置)进行突变外,采样技术之间也是可以突变的,因为对于一些特定的几何场景,一些采样技术会优于另一些采样技术。在蒙特卡洛方法中,有一类方法可以将原始的单个马尔可夫链按照某种度量进行区分,注意这种区分并不是空间上的划分,而是每种区分本身都是一个独立的马尔可夫链,只是遵循不同的转移概率分布,这种方法称为总体蒙特卡洛方法,其中一个具体算法是所谓模拟退火的思路,想象一下一个物体由高温逐渐冷却的过程,在其中的每一个温度下,粒子之间都是出于一种平衡状态的,然而在不同温度下物质之间的转移概率分布是不一样的,这种思路使我们可以通过寻找一种影响状态转移的因素,并将该因素对应的状态转移定义为一个子平衡系统,通过在这些子系统之间跳跃,我们可以寻找到最快的遍历全部状态的方式。显然路径的不同的采样技术就是一个这样的因素,每种采样技术都可以产生一个独立的平衡系统,但是对于某些路径,另一些采样技术可能是更有效的,通过在路径之间的跳跃,我们可以寻找最快收敛的方法。这些思路在近几年的MMLT和RJMCMC算法中有着重要运用。

微分几何/流形

传统的路径的采样都是完全随机的,例如无论是基于蒙特卡洛方法的单/双向路径追踪,还是基于马尔可夫链蒙特卡洛方法的梅特波利斯光照传输等,本质上都是使用ray tracing的方式从每个顶点的BRDF函数对方向进行随机采样以形成一条路径,这些方法都是基于对场景的几何信息是未知的。如果我们能够结合场景的几何信息,那么能否更有效地产生一条路径呢?这就是近几年非常重要的流形探索算法的核心思路。流形是指一个用一个隐函数描述的几何体,它是欧几里得空间的一个部分,它的整个几何体是通过局部的关系描述的,而不是像欧几里得空间其用全局的位置等信息描述,这种局部特征使得我们可以很好地探索场景的几何信息。由于反射定理和折射定理也是基于局部的定理,结合这些局部几何信息(往往是指能够获得几何体局部位置的变化,如导数等),我们可以得出光照传输的局部微分信息,而根据牛顿方法,如果已知几何体各个位置处的微分信息,则我们可以通过一系列连续迭代的过程寻找到一个给定函数的根的近似值,这用在流形中即是我们能够通过确定性的方法“找出”一条相似路径,这就是流形探索的核心思路,它用于梅特波利斯算法中高效地寻找相似路径。

有限元方法

如果光照的分布函数具有较低的频率,例如对于由漫反射表面构成的场景,我们可以将被积函数进行比较低分辨率的划分,然后对每个较大的区间使用一个值进行近似,这种方法就是有限元方法,在渲染中称为辐射度方法,在该方法中,场景被划分为一些曲面片,然后通过预计算出这些曲面片之间近似的光照传输,以形成一个传输矩阵,那么对于任意给定光照,我们便可以通过该矩阵的线性变换计算这些光照的传输结果。

迭代法

在辐射度方法中,我们通过预计算得到一个光照传输矩阵,它可以将任意一个给定的光源分布进行线性变换得到最终的光照结果。对于线性方程组的求解,数学上常用的方法是高斯消元法,它们通过对方程组的系数构成的矩阵执行一系列行交换操作将其转换为一个上三角矩阵(upper triangular matrix)进行求解。然而这样精确求解的方法在数字计算机中运用时却会遭遇被称为取整误差带来的问题。 在数字计算中,一个实数被保存为浮点数的形式 ,计算机中存储尾数的数字位是有限的,如果有 n 个数字位供存储,那么超 出 n 的部分则按四舍五入法进行取整,取整后被存储进计算机的值称为存储值, 上述的高斯消元法是由一系列操作组成的,对于每一次操作计算,它都需要将结果写回到内存中供后续的计算使用,每次存储都可能出现这种取整误差,随着整个消元法的进行,这些误差被传播并累计下去,导致最终结果出现比较大的误差,辐射度方法中矩阵的维度更是可能上万,这种误差是不可能忽略的。 高斯消元法计算的是一个直接的结果,它没有提供一种修正的机制,对于这样的误差,我们希望能够有一种修正的机制用于通过一个迭代过程将误差逼近至某个可接受的范围。所以在计算机中,我们通常使用迭代法来求解线性方程组,例如前面介绍的牛顿迭代法,它每次计算的可能不是一个直接准确的结 果,但是它提供一种机制使可以逐渐收敛到正确结果,在这个收敛过程中,我们就有机会将最终结果限定在一个可接受的误差范围。 常见的迭代法如雅可比方法,高斯-赛德尔方法等。此外,你还可以对传输矩阵执行分解以得出一个全局的传输操作符。

概率密度估计

在回归分析中,对于给定的一些数据抽样值,我们可以根据这些样本拟合出一个真实函数出来,例如核估计通过对周围一定邻域范围内的样本求加权平均来计算某个位置的真实值,与此类似,核密度估计方法则是要根据一些(往往具有相同值)的样本拟合出一个概率密度函数,因此我们可以首先将光子根据光照传输随机分布到场景表面上形成一个光子图,然后通过对这些光子执行概率密度估计来计算出它的光照分布,然后再从摄像机收集这些光照来计算最终看到的图像的分布,这就是光子映射的基本思路。和回归的思路类似,概率密度估计通过对周围的样本进行平滑来拟合概率密度分布,这个平滑的过程导致了偏差,但是却减小了估计方差,更重要的是,将一条路径的顶点与该顶点附近的光子进行“合并”以产生一条全路径,这相比于前面介绍的双向路径追踪的顶点“连接”,它大大提升了漫反射顶点与光泽路径的连接效率,使得其成为渲染如焦散效果的最有效的方法,如今,基于概率密度估计的光子映射方法也几乎是离线渲染器的标配。

【上述以及更多渲染相关数学知识以后在本站会以系列的形式更详细介绍】

上述所有这些数学方法都会在《全局光照技术》中详细讨论,并且是以比较容易理解的方式讨论,我的目标是甚至不需要你专门去查询和复习相关数学概念,就可以理解它们的基本意义以及在渲染中的运用。

《全局光照技术》正在摩点网众筹预购,该书历时三年创作,为了更好的理解这些数学概念及思路,以便为了更好的学习图形学,建议您够买一本《全局光照技术》,这也是对我写作的一种鼓励和支持,感谢!

来自在校学生的心声!

在一个人一生的成长过程中,在年少时期,或者还未进入社会的时期,或者还没意识到某些知识重要性的时期,能够有机会获得一本优秀的图书,对一个人一生的影响是巨大的!
 
对于我来讲,我在初中的时候一个偶然的机会有幸在一个出租小说的书店里一眼扫到了角落里一本培根的《人生论随笔》,在那个同学们都在阅读古龙,金庸武侠江湖的时代,我走进了培根的世界,那些对人生的智慧而朴实的描述,奠定了我现在整个人的为人性格,学习,做事,感知这个世界等各方面的基础,我整个一生都在庆幸我在年少时期遇到了那本书,那个时候我还不懂得也未曾思考过许多关于人生的事情,我时常感叹如果没有那本书,我的人生一定会完全不一样,也不会有现在这本《全局光照技术》。所以直到今天,我认为教育一个孩子最重要的就是要在他/她年少时期选择一些非常优秀的图书,最重要的教育其实是自我教育,不管哪个时期都一样,所谓“自学”不仅仅是成年人的专项。
 
我相信,对于一名还未真正走进计算机图形学工业实践之前,《全局光照技术》之于一名在校学生,其亦可能具有培根的《人生论随便》之于我性格的功效!于是考虑到在校学生的经济条件有限,《全局光照技术》在开始预订之前就提供了一个给在校学生和研究者提供教育特惠的申请通道,任何在校学生都可以凭相关资格获得一张七折优惠券。
 
自开通以来,目前已经累计收到103名在校学生的申请,分别来自75所高等院校,其中2名高中生,60名专/本科生,36名硕士研究生,5名博士研究生。
 
然而,令我很意外的是,《全局光照技术》这本图书的读者群体能够覆盖从高中生到博士研究生的范围,这是一个很令人惊讶的结果,一本书由于写作风格以及知识结构的原因,通常它都是针对一个特定的人群,例如本书在写作时的假想读者一直都是工业运用中的工程师和技术美术,但事实上它收到了更加广泛领域的关注,并且这些关注不仅仅是一种想学知识的渴望,而是他/她们通过阅读试读内容之后得到一种对自己有帮助的结论和体会。
 
以下列举一些申请教育特惠学生的心声(从高中到博士研究生的顺序,出于隐私考虑这里不提供学生姓名):
 
“我是一名高三的学生,我从高一开始学习编程,高二开始研究计算机图形学。我对现阶段前沿的渲染技术很感兴趣,但可惜的是例如辐照度,IBL,LPV等等前沿的图形技术只有英文文献可以查阅。我在摩点网上发现了您的著作《全局光照技术》。从试读章节我就能感觉出这本书很适合我,可惜校学生特惠申请只向高校学生开通。不知我能否作为一个高三学生获得一个在校学生优惠的名额呢?”
— 来自湖南XXXX中学一名高中学生
 
“我在美国高中念书,我的专攻是深度学习和利用深度学习进行降噪。因为我没有教育局ID,所以我用学校edu邮箱发了一个email. 我看了Gi Book英语版的初稿,感觉质量非常高。 我想问一下我可否申请一个优惠价格呢?”
— 来自一名在美国念高中的学生
 
“作为一名学生,我很希望能够有幸获得这本书来提升我在计算机图形学领域的专业知识。”
— 长春工业大学一名本科学生
 
“真的非常感谢您,对于一位美术设计专业的学生,这本书真的太重要了。”
山东青年政治学院一名本科学生
 
“感谢您即将出版的《全局光照技术》,感谢您的慷慨~”
— 电子科技大学一名本科学生
 
“关注您所编写的书籍很长时间了,希望能够尽早读到您的大作,非常期待~”
— 哈尔滨理工大学一名本科学生
 
“我对计算机图形学,特别是渲染方面有着浓厚的兴趣,也一直在课外时间进行学习。我在今年7月的时候看到您的著作,并且下载了试读版本进行学习。您的这本《全局光照技术》可以说是我目前读过的渲染方面的中文书籍中最详细和全面的一本,使我受益匪浅,并一直期待全书完成的时候在第一时间购入学习。”
— 北京师范大学一名研究生
 
“期待您完整版的新书!感谢您为我解开了很多困惑!”
— 湖南大学一名硕士研究生
 
“一个偶然的机会了解到了这本书,阅读了试读版后,惊艳到了,我当即下定决心购买一本。再次感谢你们为图形学做出的贡献!“
— 中国科学院大学一名研究生
 
“试读版本给我很大的震撼,行文逻辑非常适合入门,很能把握读者的思维方式。读罢,很是期待其它未完成章节。共勉! ”
东南大学一名硕士研究生
 
“在读硕博连读研究生,之前阅读了试读版,一直等待正式版发行!”
— 云南大学一名博士研究生
 
看到这些来信其实很感动,人一生的意义其实是要做一些对他人有帮助的事情,这也是我一开始写作这本书就报有的信念,那些怀疑我写作动机的人,我可以告诉你,带着一种完全的功利心绝不可能达到这本书目前的质量,也定然不可能收到上述这种众多期待!
 
于此,还是再次希望各位朋友能够将这本书多推荐给您身边的朋友,同事和同学,中国图形学社区的繁荣需要整个产业人才的平均水平能够提升起来,让我们共同期望这本书能够在这个方面发挥一点作用。
 
如果您是在校学生并期望购买《全局光照技术》图书,您可以申请一张七折优惠券,然后至摩点网参与众筹预定。
 
 
感谢大家的支持!
 
秦春林
2017.12.4

9. Radiosity(已完成)

一些涉及的术语:

Finite element methods,geometrical view factor/form factor, hemi-cube, local/global line, integral geometry, iterative methods, Jacobi method, Gauss-Seidel method, global transfer operator, N-body problem, hierarchical radiosity, wavelets analysis, wavelet radiosity, Lebesgue space, Gelerkin method, orthogonal projection, orthogonal complement, haar wavelet, multiresolution analysis, discontinuity meshing, visual events, line swaths, global visibility, visibility complex, visibility skeleton, line-data refinement, point gathering, lazy wavelet transform, lifting scheme, constrained Delaunay triangulation, ppreceptually-based refinement, Enlighten, bilinear interpolation, linear extrapolation, adaptive refinement, incremental radiosity, radiosity redistribution, progressive redistribution, cross redistribution radiosity…

反向路径采样在MLT算法中的运用

今年的SIGGRAPH还是蛮有趣的,以下介绍可能是有史以来SIGGRAPH同一年同时出现三篇思路非常类似的论文:

Reversible Jump Metropolis Light Transport using Inverse Mappings
Fusing State Spaces for Markov Chain Monte Carlo Rendering
Charted Metropolis Light Transport

故事要从PSSMLT和MMLT讲起。自从1997年Eric Veach的MLT(Metropolis Light Transport)算法发表以来,这个被称为影响20世纪科技发展最重要的马尔可夫蒙特卡洛方法(MCMC,Markov Chain Monte Carlo)算法被引入到渲染领域,与传统的蒙特卡洛方法(例如路径追踪)不同的是,它通过利用样本之间的相关性来更好地探索一个分布函数,使得一些非常困难的路径可以更轻易被采样到,然而MLT算法依赖于非常好的突变策略,原始的MLT算法依赖于完全的随机采样,根本无法了解场景的一些几何信息,突变路径的接受概率极低,使得MLT算法在相当一段时间并没有太大进展。

时间到了2002年,Csaba Kelemen提出了PSSMLT算法(Simple and Robust Mutation Strategy for Metropolis Light Transport Algorithm),如下图所示,考虑到路径采样其实就是以增量的方式从每个顶点的BSDF分布从采样得到一个方向,然后使用光线投射找到该方向与表面的交点,重复迭代直到一条路径连接光源和摄像机,这个采样的过程实际上是对多个[0,1]的随机数的采样过程,这些[0,1]随机数构成一个高维的单位超立方体(unit-hypercube),这称为原采样空间(Primary sample space),所以如果直接对该空间采样,也能够得到一条路径。于是PSSMLT(Primary sample space Metropolis light Transport)算法转而对该原采样空间进行突变,这带来一些好处,例如状态转移是对称的,另外最重要的是因为使用重要性采样,原采样空间的被积函数为f/p接近为一个常数,这使得原采样空间的被积函数更平坦,采样的方差更低,考虑传统的MLT算法并没有使用重要性采样。

然而PSSMLT也是有缺点的,其中最重要的一点是它将“路径采样”当做一个黑盒子:它直观给你一些随机数,不管你使用什么方法给我一条路径就可以,例如可以使用路径追踪或者光子映射来产生一条突变路径,这种原采样空间和原始路径空间的隔离关系使得原采样空间并不会估计路径空间的特征,例如原采样空间给定一个10个[0,1]随机数,路径采样器用到第2个时发现路径以及偏离种子路径很远了,如下图所示,这种结果称为涟漪效应( ripple e ects),因为基于出射方向采样的路径追踪无法预测后续顶点的分布,某个顶点一个微小的突变可能导致后续路径发生较大的变换,从而使种子路径和突变路径差异太大而丧失相关性,进而接受率变低。由此,PSSMLT算法在将近10年间并无太大进展。

MLT算法被提出来后最重大的一个进展要数2014年Toshiya Hachisuka提出的MMLT算法(Multiplexed Metropolis Light Transport),表面上看,MMLT只是将重要性采样引入到原采样空间,例如下图左边包含三个原采样空间,每个原采样空间对应一种特定的采样技术,技术路径采样的长度,这使得可以实现这样的功能:当有些路径突变长时间无法被接受时,我们有可能通过改变采样技术太快速找到突破的路径。在下图中,路径除了在每个原采样空间内部执行突变,还可以在不同采样技术之间执行突变。

但从知识理论角度来讲,MMLT的重要意义在于它将统计中的模拟回火(simulated tempering)的思路引入到了MLT算法中,特定地,这里使用的思路主要来自序列回火(serial tempering),回火的思路源自于模拟退火(simulated annealing),模拟退火本来用于解决最优质问题,由于物体加温之后分子状态之间的转移更活跃,因此状态更易于在全局转移,而随着温度逐渐降低,状态之间的转移就逐渐减弱。所以为了求最优值,如下图中的最大值,我们首先将温度升高,然后让其慢慢冷却,在其过程中不断寻找最大值,随着温度降低,最终将停留在最大值处。

模拟回火则是借鉴了模拟退火的思路,实际上它们并无太大联系(除了名字),模拟回火就是将模拟退火中的温度看成一个离散的函数,不同的离散温度值对应着整个状态空间的一种划分,这样状态可以在每个子状态内部转移,也可以在不同状态(即温度)之间转移。在MMLT算法中,温度即是采样技术,不同的采样技术将原采样空间划分为多个子空间。

至此,MMLT算法中路径空间和原采样空间仍然是相对隔离的,虽然MMLT算法中可以在原采样控制路径使用的采样技术,但是仅限于此。也由于这种隔离,另一个问题来了,即采样技术之间的突变也可能导致涟漪效果,如下图所示,当由摄像机向光源方向的单向路径采样转变为由光源向摄像机方向的路径采样时,由于桌子的遮挡,其突变路径将产生非常大的差异,从而很难被接受。

于是,我们本文的主角出现了。在上述情况中,当采样技术发生改变时,虽然所有的[0,1]随机数并没有发生变化,但是由于使用了不同的采样技术,这些随机数被使用的方式也完全不同了,从而到时路径发生了很大的变化。因此,理想情况下,我们希望在改变采样技术时,能够保持路径不变。因此, Benedikt Bitterli于今年提出的RJMCMC(Reversible Jump Metropolis Light Transport using Inverse Mappings)使用一个反向映射方法,当从采样技术1向采样技术2转移时,它将状态1对应的原采样空间的路径在对应路径空间中的形式,通过一个反向映射转换到采样技术2对应的原采样空间,这个过程是决定性(deterministic)计算的,不含任何采样的结果,由于它们在各自的原采样空间虽然具有不同的值,但是在路径空间它们的值是相同的,因此在计算MLT算法中的接受率时,所有项被约掉,接受率变为1。由此,我们通过一个确定性的方法产生了一个不同状态之间的转移,并且它完全被接受,这种采样技术之间的转移太高效了。

而今年的另一篇论文, Jacopo Pantaleon的CMLT(Charted Metropolis Light Transport)几乎也与上述思路类似,但是强调更泛化的概念,即将原采样空间按某种标准划分成多个不同的子空间,然后在不同子空间之间进行转移,在转移的过程中使用反射映射来保持路径不变。

HISANARI OTSU的Fusing State Spaces for Markov Chain Monte Carlo Rendering在算法上稍微不同于上述两篇论文,但是其使用的核心概念,即由路径空间向原采样空间的反向映射是一致的。HISANARI OTSU的核心思路在于组合路径空间和原采样空间的优势,例如对于路径空间的Manifold Exploration,其由于探索路径的局部流形空间的特征,因此突变路径的采样效率很高,然而它却不能有效考虑路径的全局特征,例如该路径使用的采样技术的权重。因此HISANARI OTSU将当前路径的状态保存在原采样空间,这包括路径使用采样技术的权重,但是它并不直接对原采样空间执行突变,而是使用流形探索对路径执行突变,但是与流行探索直接使用突变路径不同,HISANARI OTSU将突变的结果通过反向映射转换会原采样空间,然后提取其权重值,使得可以按全局对路径的采样结果给予评估,同时兼顾局部和全局特征。

今年这几篇论文质量还是可以的,并且更是有Wojciech Jarosz,Wenzel Jakob, Carsten Dachsbacher, Anton S. Kaplanyan等这些保驾护航。

确定性的路径采样 – 微分流形在MLT算法中的运用

介绍一篇路径采样的论文,作者Wenzel Jakob是PBRT的作者之一,他2016年获得Eurographics Young Researcher Award多半是因为这篇论文,该奖项每年仅有2个名额,用于奖励过去在相关领域做出重大贡献的人(敬礼)。

Manifold Exploration: A Markov Chain Monte Carlo Technique for Rendering Scenes with Difficult Specular Transport,以及后续的相关论文:The Natural-Constraint Representation of the Path Space for Efficient Light Transport Simulation

先总结一下,这两篇论文的本质是将传统的完全随机的路径采样转变为使用微分几何确定性地计算出一条“相似”路径,这种思路在路径采样中算是一种小小的变革吧,表现在两个方面:

  1. 从路径采样方法来讲,传统的无论是基于MC的(BD)PT还是基于MCMC的MLT,PSSMLT或MMLT等,本质上每条路径的采样都是使用Ray Tracing的方式从每个顶点的BRDF函数中对方向进行随机地(randomly)采样并连接起来形成一个路径,而Manifold Exploration是确定性地(deterministic)计算出一条路径。
  2. 从光照积分公式方面看,它从欧几里得空间转变到了流形上进行研究。

传统的路径采样是完全随机的,这里的随机可以理解为采样器不会考虑任何关于场景的几何特征而“盲目的”在路径空间行走;因此,对于那些存在于很小的区域,但是被积函数的贡献值非常大的“困难”路径,往往会由于采样概率非常低而使其估计不精确;虽然MLT算法引入了路径之间的相关性,但是本质上它只是通过限制一条突变路径各个顶点的取值在欧几里得空间的某个范围内,其使用的路径采样(例如双向路径采样)仍然是盲目的,其效率仍然非常低;然而MLT算法提供了一种绝对的优势,即一旦找到一条重要路径,我们可以更小心地探索该路径附近也可能具有同样重要性的路径。

很显然,要想有效地探索这些困难路径,我们必须了解并利用路径的一些局部几何信息,这是前面流形探索以及本节半矢量空间光照传输的核心内容。然而,要想让路径采样器(这里的路径采样器是指传统的根据光线追踪的路径采样,它几乎也是目前我们介绍的以及离线渲染中使用的唯一的路径采样器)直接能够感知整个场景中的几何信息显然是不可能的,要知道,光线追踪依赖于首先随机选择一个方向,然后对该方向使用光线投射来寻找其与表面的交点并取得几何数据,而不是先根据某种场景的几何特征选择一个方向。

这种不可能事先知道场景几何特征的采样方法,使得我们转向另一种思路:即首先通过传统的路径追踪得到一条随机的合法路径,然后提取出该路径的几何特征,进而利用这些几何特征来寻找一条该路径离开附近的路径。这种思路依赖于一条已知路径,显然它不能成为一种独立的路径采样方法,然而它却正好可以用在MLT算法中,因为MLT算法寻找一条相对于当前路径的突变路径。然而需要注意的是,局部特征的表述的精确性往往被限定在很小的局部范围(如前面镜面流形表述所描述的那样),因此这些算法必须很好地保证全局遍历性的要求。

那么,应该怎样提取一条合法路径的局部几何信息呢,费马定理提供了答案。1657年,费马提出著名的最小时间原理,即自然界的行为永远以路程最短为原则。按照这个原理,光永远是选这样一条路走,以使它在最短时间内抵达目的地,这就是费马定理(Fermat principle)。费马定理描述了光照传输的特征,如果已知一条合法的光线路径,它当然满足费马原理,因此可以从中提取与光照交互有关表面的几何信息。

然而费马原理是全局的,它用于描述一条完全的路径,直接推导出这种全路径与多个表面交互的关系是非常困难的。幸运的是,局部的反射定律和折射定理与费马定理是完全等效的,局部的反射和折射定理提供了路径顶点及方向关于这些顶点局部几何信息(如位置,法线以及这些量的导数)的关系,从而我们能够从一条已知路径推导出该路径的局部几何信息。

然后,已知了一条路径的局部几何信息了,该如何利用它们来产生一条“相似”路径呢,这时牛顿方法提供了答案。我们已知的顶点局部信息是关于对应表面在该顶点处的位置和法线关于局部坐标系的导数,导数能够被运用于一阶泰勒近似中用来表述局部的函数分布,然而这种近似不能直接用来作为采样值,我们需要精确值,而牛顿方法正式利用一阶导数用迭代的方式逼近某个设定的真实函数值。

于是我们能够通过一条已知路径获得一条“相似”或“近邻”路径,这条路径在MLT算法中具有较高的接受率,因为它探索了路径的局部几何特征。更为重要的是,上述的采样过程是确定性的:给定一条当前路径,我们没有依赖任何随机过程,而是使用微分几何相关的知识直接计算出一条“相似”路径,这种由随机向确定性的转变,提升了MLT算法的效率。

这里提到两篇论文Manifold Exploration和Half Vector Light Transport正式使用了上述思路,它们都是借助费马定理将一条已知路径和其对应的局部几何信息建立起了联系,然后利用微分几何以及牛顿迭代法确定性地计算一条”相似“路径,只不过这里Manifold Exploration通过降维的方式将路径空间转变到镜面流形上,而Half Vector Light Transport将其转换到半矢量空间。

其实就是什么意思呢,如上视频所示,给定一条初始路径,它能够不需要任何随机过程直接计算出所有满足初始路径类似的几何配置,并自动满足每个顶点处反射折射定理的相邻相似路径,而这正是MLT算法非常需要的。