本篇 Paper 分享是来自于皮克斯的《RenderMan: An Advanced Path Tracing Architecture for Movie Rendering》。
简介
RenderMan 是皮克斯推出的用于渲染视觉特效的一个渲染引擎。最早的 RenderMan 基于 Reyes 的扫描线渲染算法,之后增加了包括光线追踪、次表面散射、辐射度缓存等新功能。而现代的 RenderMan 已经被重写为一个路径追踪器,支持双向路径追踪以及实时光线追踪。路径追踪与 Reyes 的算法几乎是差不多的时候(1986 年左右)被推出的,那个时候光线追踪被认为不太可能用于渲染电影,更不用说实时渲染——即使算法优美,但性能开销过大。不过随着近二十年来人类科技的发展,很多问题被克服,也就促成了实时光线追踪的出现。
早期的 RenderMan
Reyes 算法
早期 Reyes 算法的核心步骤:
分块渲染(tiled based rendering):Reyes 算法将图像划分为小块(称为“桶”,即 bucket),然后逐个渲染这些小块。这种分块渲染方法允许在渲染每个小块时,仅加载当前视图所需的几何和纹理数据,大大降低了内存需求。
生成微多边形(Micropolygons):Reyes 算法会将可见表面细分成更小的片段,并最终将每个片段网格(grid)切分成微多边形,这些微多边形的大小通常与像素相当。这样不仅能够提供高度的几何细节,还能便于位移贴图的应用。
着色与抗锯齿:每个微多边形的顶点通过表面着色器计算颜色和透明度,而抗锯齿通过对这些微多边形进行分布采样实现。由于这是在二维平面上操作,数据具有很强的局部性,抗锯齿效果也比较平滑。
运动模糊和景深:Reyes 算法在实现运动模糊和景深效果时,具有高效率和低噪声的优势。它通过增加像素采样的数量来消除噪声,而无需额外增加着色计算成本。
虽然 Reyes 的算法有着优秀的内存管理能力,但是它并不擅长处理阴影的反射。与传统方式类似,它还是需要借助阴影图和反射图来制作这些效果。
反射带来的光线追踪
为了更好更真实的反射,RenderMan 引入了光线追踪 [Whitted 1980]。光线追踪可以在不需要维护阴影图、也不需要在意阴影图的分辨率的情况下给出高质量的阴影和环境光遮罩。
光线追踪的内存访问模式比 Reyes 算法复杂:几何体可能非常复杂,尤其是当使用位移贴图或高分辨率的细节时。直接对所有几何体进行高分辨率的光线追踪不仅会导致巨大的内存需求,还会降低渲染速度。虽然主摄像机射线、来自平面表面的反射射线和指向小型光源的阴影射线具有一定的访问一致性,但总体而言,反射或阴影射线可能随时向任何方向发射。因此,场景几何数据和纹理的存取呈现出随机性。由此,RenderMan 对光线追踪的几何处理进行了一些优化:
多分辨率缓存(multi-resolution cache):通过将不同分辨率的表面缓存到内存中,并根据光线差异选择合适的分辨率。
平行测试光线与四个三角形(两个四边形)的相交情况。
尽管光线追踪在精细效果上表现优异,但在处理运动模糊和景深时,噪声和计算开销较大,与Reyes算法相比,这些场景的渲染成本仍然较高。因此,当时完全切换至光线追踪还不是最佳选择。
分布式光线追踪
RenderMan 虽然用了但没怎么用:消耗太高了,只用于计算全局光照。
分布式指的是让光线在物体表面之间多次反弹,以模拟现实世界中的漫反射现象。然而,直接对所有二次光线进行着色计算代价太高,因此需要找到更加高效的计算方法。DreamWorks 和 RenderMan 分别进行了一些改进,但即使进行了改进也还是太慢了。
基于点的方法
为了解决分布式光线追踪的这些问题,RenderMan 引入了基于点云文件的方法:通过在渲染前预计算并存储光照信息,以提高渲染效率并减少噪点。具体来说:
在正式渲染之前,首先计算并存储场景中的直接光照,将其以点云(Point Cloud)文件的形式保存下来。
通过遍历预计算的点云,逐个计算点的贡献,再将这些贡献值按照散射模型(如扩散模型)进行加权并累加,从而生成最终的次表面散射、AO 或是 GI 效果。
这种方法确实高效且没什么噪点,但问题是很多用户还是对需要维护点云文件而感到不满。而且点云的分辨率和分布会影响渲染效果,如果点云过于稀疏,可能会产生别的失真或锯齿现象。
再次引入分布式光线追踪
新的优化方法:光照缓存(Radiosity Cache [Christensen et al. 2012])。将 shader 分成独立于视线(ViewDir)(例如 diffuse)和依赖于视线(例如 specular)两个部分。视线独立的部分计算结果存入光照缓存,以供重复使用,而视线相关的部分则在每次光线交点计算时重新评估。在光照缓存中,昂贵的光照计算和纹理查询只需要进行一次,且能够在整个场景的多次渲染中重复利用。这大大降低了着色成本,并提升了渲染速度。
这种方法虽然效率提升明显,但仍有一些不足:
缺乏渐进性:分布式光线追踪的结果不具备渐进特性,无法在初步渲染图像上逐步提高质量。
缓存一致性:缓存管理可能导致不同帧之间光照结果的差异,因此在动画序列中可能会出现闪烁。
体积渲染
Reyes 算法中并没有体积渲染的部分,后来加上了,和 Houdini 的渲染器采用的技术类似:将体积分成体素(voxel),计算每个体素的颜色、透明度等,渲染每个微体积。
早期 Reyes 算法的局限性
文中提到的四个主要的局限性:
处理高密度几何的效率低下。
不支持实例化。
体积渲染效率低。
难以扩展到 16 线程以上的多核系统。
整个 Paper 的第二部分总体展示了 RenderMan 渲染技术从 Reyes 算法向路径追踪的演变过程,充分体现了 CG 中 tradeoff 的特性:每个阶段的技术选择和优化都反映了对效率、性能和图像质量的不断追求,最终促成了更加统一和灵活的现代路径追踪架构,使得RenderMan能够适应当今电影制作中复杂的渲染需求,然而又在优化的过程中在时间和空间之间不断地做取舍。当且仅当在图形算法和硬件上有突破时,很多以前做不到的技术之后才得以实现。
现代的 RenderMan
RenderMan的现代化转型聚焦于路径追踪,因为它能提供更加统一、灵活的渲染流程。路径追踪具备以下优势:
进度渲染和交互式渲染:路径追踪适合渐进式和交互式渲染,在编辑时能快速生成低质量图像供参考,并逐步提升质量。
几何复杂度的处理:路径追踪可以通过对象实例化等技术有效管理几何复杂度。
高效的降噪与采样优化:随着降噪和采样技术的改进,路径追踪的噪点和收敛速度问题得以解决。
统一的光照模型:路径追踪无需额外的预处理步骤,能够在一个单一的(single-pass)渲染流程中处理直接和间接光照。
另外,其架构也具有极强的可拓展性——参考 pbrt 之后的产物。一些关键的组件:
材质接口(bxdfs):RenderMan允许用户定义自定义材质,称为bxdf,包括各种表面散射和体积散射模型。用户可以通过 API 访问 EvaluateSample() 和 GenerateSample() 等方法,实现自定义光照的生成和评估。
光照传输接口(integrators):RenderMan 通过 integrators 接口允许用户定义自己的光照传输算法。integrators 可以管理路径追踪中的光线生成和采样,比如双向路径追踪和体积光照等。
其他插件类型:RenderMan 还支持表面位移、光源、光照过滤器、摄像机投影和样本过滤等插件,用户可以通过这些接口控制渲染的各个方面。
这一部分与 pbrt 的实现思路几乎是一模一样的,从而可以看出 pbrt 这本书的含金量!工业界和学术界的双重教科书。每一个图形程序员都应该从第一页读到最后一页。
材质接口 bxdf
两个主要的接口:
EvaluateSample():
输入:wi, wo,
输出:rgb bxdf 数值,两个概率密度函数分别对应前向散射和后向散射。
GenerateSampler()
输入:wi
输出:wo(遵循某个“随机”生成的方式)
文中提到现在的技术指导如果要搞个材质比以前难多了:ta 得会 C++,图形学,概率论,微积分,信号,采样,光学……只能说感同身受了。
RenderMan 本身提供一些已经写好的 bxdf (基本可以认为指的就是材质球):例如朗伯漫反射、理想镜面、次表面散射下的皮肤、毛发等。会玩的用户也可以自己定义 bxdf。
积分器
积分器主要的作用就是(数值)计算辐射亮度 radiance。两个主要的接口:
GetNearestHits()
输出:(版本1)返回 HitInfo 或(版本2)返回光线击中的着色群。
GetTransmission()
输出:两点之间的穿透率(用于进行体积渲染计算)。
场景处理
随着电影画面变得复杂,场景复杂度提高,需要处理的数据量也变得极为恐怖,有的一帧就要大几十 GB。RenderMan 采用了以下这些措施来处理场景。
处理几何体
RenderMan 会将包含成千上万个多边形的大型网格分割成更小的部分,以创建具有更小叶节点的层次包围体(BVH),优化加速结构。
RenderMan 根据场景中的路径差异,自动选择适当的几何细分级别。在靠近摄像机的物体上使用高分辨率细分,而对于远离视角或屏幕上占比小的物体。
RenderMan 通过实例化来有效地管理大量相同的对象,如《Piper》短片中的沙粒,避免重复存储相同的几何数据,只需存储变换和材质的不同配置即可。
处理纹理
RenderMan 延续了 Peachey [1990] 的纹理缓存方法,改进了多线程查找和基于光线差异的 MIP 映射支持,使其可以在复杂场景中高效加载所需的纹理。
RenderMan 支持 Ptex 格式,这种纹理格式允许每个网格面有独立的 MIP 映射(不过这种格式可能会导致缓存出现问题)。
RenderMan 还提供 3D 砖块贴图(brick maps)[Christensen and Batali 2004],适用于需要在体积中存储纹理的场景,例如云雾或烟尘等体积效果。
处理光照
《寻梦环游记》中有八百万(?????)个点光源,就是这一幕。
RenderMan 通过采样子集的方法来优化光照计算,避免对所有光源进行采样。
另外,配合多重重要性采样(Multiple Importance Sampling)[Veach and Guibas 1995],结合了材质和光源的重要性采样结果,以减少噪声。对于非漫反射材质,RenderMan 还会应用联合重要性采样(Joint Importance (of 2 bxdf) Sampling),以更准确地选择光源方向 —— 回顾 pbrt 的多重重要性采样那一节,就能理解联合重要性采样的奇妙了。再次感叹计算机图形中的这些天才的数学发现。
最后,RenderMan 支持用户定义的光照过滤器插件,如遮光门(barn door)、渐变色等,这些过滤器在场景中能动态调整光源效果。
处理并行
RenderMan 的现代架构为多核处理进行了优化,以便在具有几十个核心的现代处理器上高效运行。RenderMan 使用 Intel 的 TBB(Thread Building Blocks)库来管理多线程任务,使得在高复杂度场景中能够更好地利用多核 CPU。此外,RenderMan 团队通过重组计算任务和消除瓶颈,使得即使在高达 72 核的系统中仍保持高效。
数据处理
曲面细分
RenderMan 根据曲面的屏幕尺寸来选择合适的细分级别,通常会将每个微多边形的目标大小设为一个像素。它支持两种细分方式:
完整细分:在光线第一次击中物体时对整个表面进行细分,确保相邻的曲面片段具有匹配的顶点。
按需细分:仅在光线需要访问表面特定区域时细分,这种方式可能导致边缘之间的细分不匹配,因此可能会出现小的视觉缺陷(如光线漏过的“针孔”现象)。
BVH
大场景肯定都会用 BVH。在 BVH 树中,每个节点都包含包围盒,叶节点包含实际的几何体。当光线沿着 BVH 树遍历时,只需处理与当前光线相关的节点。为了支持异步加载和动态几何处理,RenderMan 在光线穿过 BVH 时会根据需要自动重新构建部分树结构。
相交测试
RenderMan 会将最多 64 条具有一致方向的光线打包成一个光线束(ray bundle),在 BVH 中并行遍历。在每个叶节点中,光线束会与 4 到 8 个三角形或四边形表面进行交点测试,这种批量化操作可以充分利用向量化处理,提升处理效率。
此外,RenderMan 通过实例化技术表示重复对象,仅存储一次几何数据,并通过变换矩阵和材质 ID 管理不同的实例。
在渲染毛发和草叶等细小几何体时,RenderMan 会使用扁平“丝带状”或圆柱状曲线表示。曲线可以分割为多个小段,并采用自适应包围盒进行加速。光线会沿着曲线段进行交点测试,以确保毛发等复杂结构的渲染效率。
数值精度
在光线追踪过程中,RenderMan 需要调整光线的起始位置,以避免浮点精度问题导致的自相交错误。RenderMan 使用两种偏移方式:
几何细分偏移:当相邻曲面片段的细分不一致时,使用偏移来避免边界上的光线漏过。
浮点精度偏移:对远离坐标原点的几何体,光线起点的偏移量要大于浮点数精度,以避免由于数值误差导致的错误。
想起来在 pbrt 中还记得射线的定义是包含 tmin 和 tmax 的,并且使用它们来判断是否与场景相交。
这也是为了防止自相交采取的一个措施,也是为了避免化整误差导致射线和发射自己的平面相交了。
老生常谈的动态模糊和景深
RenderMan 通过为每条光线分配一个随机时间来实现运动模糊,同时对同一像素内的时间进行分层采样,以降低噪点。对于景深效果,RenderMan 在像素位置和镜头位置上进行4D分层采样,确保景深效果清晰且平滑。
路径微分
RenderMan 采用了一种简化的路径微分方法,仅使用两个浮点数来表示光线的初始半径和传播距离的变化率。这种简化的光线差异计算对于像素进行多次采样的场景已足够,且降低了计算成本。
渐进渲染
样本序列
RenderMan需要高质量的样本序列来保证渐进渲染的效率和图像质量。常见的采样方法有以下两种:
有限样本集:传统的抖动采样(jittered sampling)和多抖动采样(multi-jittered sampling)都属于这一类。这些样本集在图像最终渲染时效果较好,但在渐进式渲染中,初始采样的质量可能不够高,影响交互式渲染的实时反馈效果。
渐进样本序列:这种方法生成一个无穷长的样本序列,每一层级都经过精心分布,保证从少量样本到大量样本的每个阶段都具有良好的分布效果,适用于渐进渲染。RenderMan 采用渐进多抖动(progressive multi-jittered, pmj02)样本序列,并对高维采样进行本地混洗,从而在3D、4D甚至更高维度上都保证了采样的高质量。
自适应的像素采样
RenderMan 会根据图像中不同区域的复杂度自动调整采样密度。平坦区域或空白背景很快收敛,而在高频细节区域、半影和高光等复杂区域则需要更高的采样密度。自适应采样的关键步骤包括:
对比度误差测量:RenderMan 通过对比度来判断某区域是否收敛,对比度方法不受光照曝光的影响,能在多种曝光情况下保持一致的噪声水平。
相邻像素重置:一旦检测到某像素的采样结果超出收敛标准,则重新采样该像素及其相邻区域,以更准确地捕获视觉细节。
阈值调节:在制作过程中,用户可以对特定对象设置更严格的收敛标准,并控制暗区的采样限制,从而在需要时进一步优化采样效率。
“检查点”
通常我们说的渐进渲染是一种从低质量快速生成图像逐步提高到高质量的渲染方法,特别适合于交互式渲染需求。RenderMan 的渐进渲染还支持"检查点(checkpoint)"功能,即在渲染中定期生成可供查看的 EXR 格式中间图像。
检查点的主要优点包括:
检查点恢复:如果渲染意外中断,可以从检查点恢复渲染进度,避免重新渲染整个图像。
时间限制:用户可以设置渲染的最大时间限制,RenderMan 在达到时间后生成检查点图像并安全退出。
快速预览:检查点生成的低质量图像可供艺术家快速参考,有助于及时调整渲染设置。
这样的渲染选项其实现在大部分的渲染引擎(blender, vray, ...)都有相关的支持。RenderMan 在当时可以算是走在了行业的前面。
实时渲染
路径选择
在路径追踪中,光线路径的选择决定了光照计算的效率和图像质量。选择合适的路径可以确保光线优先穿过关键区域,减少不必要的计算,从而提高渲染效率。RenderMan 通过路径选择和操作来控制路径生成、路径采样的权重分布,使得光线能够更有效地捕捉场景中的重要光照信息。
在 pbrt 中也有相关介绍光路径的章节,可以用 Heckbert 的正则表示法来表达光路径。虽然这里不重要,但 RenderMan 在某些情况下会引导光线优先探索间接光照强的区域。例如,在间接光照和全局照明的复杂场景中,引导路径可以帮助光线找到有效的光照来源,提高采样效率(这应该是就是 next event estimate, NEE)。
交互式渲染
RenderMan引入了轻量级场景图(lightweight scene graph),以适应交互式渲染中的快速场景管理需求。这个场景图设计精简,旨在高效处理复杂场景中的几何体、材质和光源调整,同时不会增加渲染管线的负担。轻量级场景图的特性包括:
快速更新和增量式更改:轻量级场景图允许在场景中进行局部修改,而无需重新构建整个场景数据。这种增量式更新特别适用于交互式渲染,能够立即反映出光照或材质的调整效果。
优化内存管理:轻量级场景图仅存储必要的场景数据,使得内存使用更加高效。这对于交互式渲染至关重要,因为复杂场景可能包含大量几何体和纹理数据,通过减少不必要的数据存储,提升了响应速度。
便于与其他系统集成:轻量级场景图可以与 DCC 工具中的场景数据相集成,使得数据转换过程更加顺畅,减少了不同软件间的转换负担。
它还提供了被称为 Riley 的底层渲染接口,其专为交互式渲染设计,提供对渲染器的直接访问和控制。Riley 允许开发人员通过编程接口管理渲染过程中的关键元素,包括几何体、材质、光源和摄像机等设置。Riley 的特性包括:
高效的场景操作:Riley 支持对场景进行直接、低延迟的操作,例如增删几何体、修改光源和材质等。这使得艺术家在场景中进行实时编辑时可以迅速获得反馈,提升了工作效率。
灵活的渲染控制:Riley 提供了丰富的 API 接口,允许开发者灵活地控制渲染参数和效果。例如,开发者可以使用Riley 控制光照和反射的采样密度,动态调整渲染质量,以适应不同的交互需求。
与轻量级场景图协作:Riley 与轻量级场景图紧密结合,场景图中的数据可以直接传递到 Riley 进行渲染,从而实现高效的数据流和更快的渲染响应。
这些技术由之前的两个研究—— Lpic 和 Lumiere 提供了先例。Lpics 负责管理渲染场景中的几何体、材质、光源等元素,是一个轻量化的场景图管理系统。Lumiere 是一个专注于光照管理和设置的系统。
简化的积分器
使用一些甚至可以不用做光线追踪的积分器可以使得出图速度极快,这种渲染方式可以用来快速查看固有色、深度、法线等。特别地,环境光遮蔽积分器(Ambient Occlusion Integrator)用于模拟阴影区域的暗淡效果。AO 积分器通过检测物体表面附近的遮挡情况来生成简单的阴影效果,这种方法计算开销低,但能够提供适当的深度感,通常用于快速概念图或测试图。
路径追踪
整合的技术
除了常见的优化技术(俄罗斯轮盘赌、NEE等),也有一些在 RenderMan 中独特的技术,比如单独设置物体的可见性(是否对相机、光线、阴影射线等可见),可以关闭焦散,可以将初始弹射设置为高于 1 。
次表面散射
通过整合 Dipole Diffusion 可以做出比较卡通的皮肤效果,之后皮克斯又开发了一种暴力的路径追踪随机游走蒙特卡洛方法。共同在一起提供了的非常逼真的次表面散射渲染效果。
体积渲染
使用 delta tracking 处理。渲染信息描述(比如透射率、散射相位函数等)基本上是通过读取 OpenVDB 或者 Field3D 文件。
高级支持
双向路径追踪:优势在于间接光照和强焦散场景。
统一路径采样:双向路径追踪和渐进式光子映射的组合。(文中提到 RenderMan 开发团队相信光子映射必定是未来的最高级算法的其中一部分,因此 RenderMan 肯定是支持光子映射的——回顾 pbrt 中光子映射的开发难点,主要是在于需要知道怎么从光源进行随机采样,同时也要能支持重要性方程)。
Metroplis: 能够找到不好发现的光路径。但是现在 Metropolis 还没啥用,希望未来的 paper 能够进一步挖掘。等到那一天到来,RenderMan 就会支持 Metropolis 了。
参考资料:
Comments