迪士尼 Hyperion 渲染器的设计与演进
BRENT BURLEY, DAVID ADLER, MATT JEN-YUAN CHIANG, HANK DRISKILL, RALF HABEL, PATRICK KELLY, PETER KUTZ, YINING KARL LI, 和 DANIEL TEECE,华特迪士尼动画工作室




图 1. 来自《超能陆战队》(Big Hero 6,左上)、《疯狂动物城》(Zootopia,右上)、《海洋奇缘》(Moana,左下)和《雪宝的冰雪大冒险》(Olaf’s Frozen Adventure,右下)的最终渲染帧,全部使用迪士尼的 Hyperion 渲染器渲染。
华特迪士尼动画工作室已转向基于 path tracing 的 global illumination,作为以艺术家效率为名、向更“brute-force”的 physically based rendering 演进的一部分。为了在不牺牲几何或 shading 复杂度的前提下实现这一目标,我们基于一种新颖的架构构建了 Hyperion 渲染器:它从大型、排序后的 ray batch 中提取 traversal 与 shading coherence。在本文中,我们描述架构并讨论关键设计取舍;也会解释如何在 physically based renderer 中提供艺术控制,并用多个制作案例说明“自研渲染器随 production 需求演化”的价值。
1 引言
自 1990 年代早期以来,华特迪士尼动画工作室的计算机图形(CG)图像渲染一直使用 Pixar 的 RenderMan 中的 Reyes 算法(Cook 等人,1987)来完成。最近,ray-traced global illumination(GI)承诺通过提供更即时的渲染反馈,并消除与 shadow map 和 point cloud 相关的繁重数据管理负担,为艺术家带来显著的生产力提升。然而,最初尝试用 ray-traced GI 渲染我们现有的制作场景并未成功:对 texture map 的非一致性访问让间接 ray hit 的 shading 变得低效,而且我们难以将场景装入当时 ray-tracing renderer 所要求的内存中。
为了克服这些限制,我们创建了一种新的渲染架构,该架构以大批量方式追踪和 shading 光线,首先在场景遍历期间对每个 batch 进行排序以获得几何一致性,然后在 shading 期间对 ray hit 进行排序以获得 texture 一致性(Eisenacher 等人,2013)。这种流式架构是我们专有 renderer Hyperion 的核心:它使我们能够做 ray-traced GI,而无需牺牲几何或 shading 细节。从《超能陆战队》的制作开始,Hyperion 已被用于渲染我们工作室中的所有 CG 图像(图 1)。
在本文中,我们首先在第 2 节中回顾我们开发新渲染器的动机和理念。我们在第 3 节中详细阐述系统的基本方面。在第 4 节中,我们展示了一些重要功能的案例研究,这些功能基于特定的制作需求推动了 Hyperion 设计的演进。然后,我们在第 5 节中讨论如何使 path tracing 在制作中切实可行——我们如何减少 noise、调试问题,并在基于物理的渲染器的限制内提供艺术控制。最后,我们在第 6 节中讨论我们设计决策的权衡与局限性,并对未来方向提出一些建议。
2 背景
2.1 为什么需要新渲染器?
历史上,华特迪士尼动画工作室的渲染围绕着一个基于“绘制式程序化”理念的高效外观开发流程而演进。texture 构成了我们 shading 的基础,在创作和使用方面都具有优势,通常每个表面会应用数十个独特的 texture 层。在 shading 过程中,texture 经常使用表达式(Selle 等人,2011)进行调整和分层,从而在一个一致、可预测的界面中提供艺术灵活性和控制。虽然表达式也可用于渲染内图案生成,但它们更常被烘焙到 texture 中,以获得高质量过滤、通过 mipmap 实现的内建细节层次以及可预测的成本等好处。
这种 texture 密集型工作流程已在我们所有制作中成功应用了十多年。最近,随着向基于物理的渲染的转变,采用诸如基于点的 global illumination(Point-Based Global Illumination,Christensen 2010)等技术,使渲染图像的外观更加丰富,但这是有代价的。艺术家们承受着漫长的迭代时间,必须在渲染前将光照烘焙到庞大的点云文件中。作为替代方案,光线追踪 global illumination 的即时性承诺提高艺术家效率,但也带来了其他担忧。使用我们的 texture 时,shading 次级光线时的非一致性 texture 访问被证明是难以承受的。光线追踪要求场景完全驻留在内存中,这也将迫使我们缩减场景复杂度;这是我们无法以减少迭代时间为名而强加的事情。例如,在现有的光线追踪渲染器中尝试渲染《超能陆战队》中哪怕一个城市街区的一小部分,都超出了我们当时系统 64GB 的物理内存限制,而我们估计我们的需求可能要大一个数量级。相比之下,这些正是 Reyes 架构擅长处理的领域——通过一次一个表面地细分和 shading 场景,Reyes 支持在大于可用内存的几何体上进行一致的 texture 访问。这些观察引出了一个问题:是否有可能将 Reyes 的核心优势与光线追踪 global illumination 的承诺结合起来?具体来说,我们能否以流式方式执行 GI 渲染,例如,对相机光线遍历场景一次,并对每个间接反弹额外遍历一次?
2.2 开发 Hyperion
为了探索“流式 GI”的想法,我们实现了多个实验性渲染器。最初,我们尝试了各种有偏方法,例如追踪“积分锥”,希望所需的锥体数量远少于光线。我们还考虑在中间命中点之间共享辐射度估计,但这种方法使得对图像质量和正确性的推理变得困难。最终,我们发现 Monte Carlo path tracing 是最简单且最稳健的方法,但这意味着我们将拥有比预期多得多的光线,多到无法全部放入内存。因此,我们将重点转向最大化遍历和 shading 一致性,以最小化我们访问每个场景对象的次数。
在我们的最终原型(Eisenacher 等人,2013)中,使用多达 3300 万条 ray 的 batch 进行 sorted deferred path tracing,提供了足够的 shading coherence:即使所有 texture 每个 batch 都要从网络重新读取,也依然能保持高效的 texturing。我们还展示了对于 out-of-core geometry 仅 2× 的性能损失:当场景几何体过大无法放入主内存时,对象会在 ray intersection 期间被驱逐并按需重新载入。我们原型的结果足够令人信服,以至于我们决定编写一个针对当时正在进行的制作《超能陆战队》的渲染器。这给了我们大约 18 个月的时间来开发 Hyperion,添加诸如运动模糊、实例化、毛发、次表面散射、体积以及各种艺术控制等功能。Hyperion 还需要一些功能,使艺术家和技术人员能够调试他们的场景。而且,由于我们无法承受将图像渲染到收敛,我们需要开发一个稳健的 denoising 解决方案。
我们的目标雄心勃勃,但在为《Big Hero 6》开发 Hyperion 的过程中,我们拥有巨大的优势:我们只需要实现对制作至关重要的功能,并且始终有大量具有代表性的测试数据可用,以驱动开发。为了降低风险,我们最初专注于那些没有变通方案的功能,推迟了运动模糊和体积效果等可以通过合成技术处理的功能,不过幸运的是,我们及时完成了这些附加功能。我们最初保留了之前的渲染管线作为应急计划,但在制作过程中放弃了这一计划,因为维护两条功能对等的管线带来了巨大开销,而且艺术家们已经依赖上新渲染器带来的好处。我们最终的成功得益于《Big Hero 6》制作团队的深度投入。
2.3 设计理念
Hyperion 延续了我们向基于物理的渲染(physically based rendering,Burley 2012, 2015)的迁移。作为一家动画工作室,我们采用基于物理的渲染的主要动机是提高艺术家的生产力,而非明确追求更高的真实感。它承诺以最少的努力获得丰富、可信的结果,并为艺术迭代提供比临时拼凑的渲染更好的起点。为了满足艺术指导——这从来都不是严格照片级的——我们叠加了非物理的艺术控制,这些将在第 5.3 节中讨论。随着每一部制作带来新的渲染挑战,我们不断添加功能并演进架构。
为了维护我们艺术家生产力的首要目标,我们在所有工作中都力求保持以下理念:
— 简单优于灵活。我们尽量不让用户承担非艺术性的控制。例如,我们不暴露光线偏移选项、不提供每瓣或每材质的采样控制,也不提供积分策略的选择。即使在艺术控制方面,我们也努力做到尽可能少,并定期审查我们的控制项,看看哪些可以移除。
——通用方案优于专用方案。我们更倾向于具有稳健行为和可预测性能的解决方案,而不是针对特殊情况进行优化。
——艺术家迭代优于最终帧效率。需要手动调参或耗时预处理的方法会抑制迭代。无偏渐进式渲染允许艺术家在 noise 图像上快速迭代,理想情况下最终帧只需渲染一次。
这一理念的自然结果是不断走向越来越暴力的解决方案。正如我们在整篇文章中(特别是在第 4.2、4.4 和 4.5 节)所描述的,我们一直在稳步地用 Monte Carlo 解替换有偏近似。在每一种情况下,这样做的动机都是艺术家的效率,而在每一种情况下,我们图像的质量和一致性也得到了提高。此外,拥有内部渲染器使我们能够根据这一理念,为艺术家的需求量身定制解决方案,拥有很大的自由度。
3 系统描述
在本节中,我们将介绍 Hyperion 架构的细节。Hyperion 的高层处理流程如算法 1 所示。
3.1 迭代
为了提供渐进式反馈,我们的渲染被划分为多个迭代,每次迭代形成一幅完整、一致的图像,后续迭代增加每像素采样数(SPP),以收敛到最终图像。我们从 4 或 16 SPP 开始,后续迭代加倍,每次迭代最多 256 SPP。
迭代之间的间隔提供了执行各种操作的机会:
——计算方差估计并调整自适应采样的像素预算,将在第 5.1 节讨论。
— ——细化光源重要性缓存,将在第 4.1.1 节讨论。
— 将帧缓冲区写入磁盘,允许艺术家在长时间渲染过程中审查甚至使用进行中的图像进行合成。
—记录检查点信息,以便在中断时重新启动渲染器。
—细化光子图,详见第4.3.1节。
— 使用更紧密的包围盒更新顶层层次结构(第3.3节),以适配最近扩展的程序化对象。
— 记录每次迭代的统计信息。
虽然其中一些操作仅在迭代之间有效,但在迭代之间更新数据结构也能带来效率优势。在一次迭代期间,大多数数据结构是只读的,允许线程之间无锁共享。在迭代之间,这些结构是只写的,避免了读/写同步的需要。
算法1:Hyperion 渲染器伪代码
函数 RENDER RUNONEITERATION // 生成初始缓存点 计算光子图概率质量函数 当未完成时执行 RUNONEITERATION 函数 RUNONEITERATION 生成并追踪光子 生成相机光线 PROCESSRAYS 更新自适应采样器 更新缓存点 保存图像文件和检查点 函数 PROCESSRAYS 对于每个 rayBatch 执行 // 遍历:cones ← 将 rayBatch 光线分组并排序为锥体 hits ← 遍历场景,将锥体及其光线与几何体求交 // shading:hitGroups ← 按 shading 器和对象对命中点进行排序和分组 对于 hitGroups 中的每个 hitGroup 执行 sortedHits ← 按面 ID 对 hitGroup 的命中点排序 对于 sortedHits 中的每个 hit 执行 // 这些步骤将结果溅射到帧缓冲区并生成散射光线 积分体积 shading 表面
3.2 相干光线批次
Hyperion 以批次方式处理光线以最大化相干性。我们一次处理一个批次,首先将批次中的所有光线与场景求交以生成命中点,然后对 shading 命中点,将发射辐射率乘以路径吞吐量溅射到帧缓冲区,或生成新光线并将其排入未来的批次。我们通过多种方式使用光线批次来提高相干性:
— 主光线按照空间填充的 Z-order 曲线生成。
—所有光线(主光线和次级光线)按主导半轴(±X | ±Y | ±Z)组织到不同的批次中,这意味着每个批次具有近似的前后遍历顺序。
— 在遍历之前,每个批次中的光线被递归排序,首先按原点,然后按时间,最后按方向。
— 在 shading 之前,命中点按场景对象和网格面索引排序。
—就绪的批次被组织成一个栈,最近填充的批次因此成为下一个要处理的批次。这产生了一种广泛的深度优先遍历,提高了局部性,并控制了待处理批次的数量。
我们观察到,遍历和 shading 一致性都随批次大小而提升,并发现3300万条光线是我们系统中实际可用的最大批次大小。
3.3 场景遍历
我们的场景由场景对象组成,每个对象引用一个可追踪对象(traceable)和一个 shading 器(shader)。典型的可追踪对象是单个网格,或曲线、球形粒子或实例的集合。
可追踪对象与光线求交以产生光线命中,每个可追踪对象负责自身的遍历和加速结构,通常是针对其特定需求优化的某种形式的包围体层次结构(BVH)。
在 global illumination 渲染中,实现一致的光线遍历同时保持单条光线的高效遍历速度是一个重大挑战(Barringer and Akenine-Möller 2014)。我们将层次结构分为两级:
— 顶层层次结构与可追踪对象的包围盒求交,确定一条光线可能命中哪些可追踪对象。我们使用32条光线组成的光线包(packet)对该 BVH 进行遍历。
— 底层层次结构与单个可追踪对象(例如其三角形)求交。我们使用单条光线对该 BVH 进行遍历。
由于每个批次中包含大量光线,无论光线深度如何,我们都能形成一致的光线包。对于光线包求交,我们发现使用包围锥(bounding cones)是有利的,避免了将光线包中的每条光线分别与每个包围盒求交;我们发现锥-盒求交的成本与单条光线求交相似,并且我们利用 SIMD 一次对多个锥进行求交。此外,我们发现大批次大小有助于提取一致的光线流集合,这些集合可与其他光线包遍历方法(如 Fuetterling 等人(2015)的方法)兼容使用。
我们按需加载场景对象,以避免不可达对象的内存开销,并通过允许重新加载被淘汰的对象来实现核外渲染。光线包在层次结构中遍历,并在需要加载的可追踪对象处排队。如果展开某个可追踪对象所需的内存会导致渲染进程超出预设的内存限制,则按近似最近最少使用顺序淘汰对象。淘汰分两个阶段进行:首先尽可能收缩可追踪对象,然后完全淘汰。收缩的一个例子是丢弃 BVH 的内部节点包围盒,这些包围盒可以很容易地从其叶节点恢复。
虽然主层次结构仅对批量的辐射度查询光线执行光线包遍历,但 shading 器可以立即为其他目的追踪单条光线。其中一个目的是次表面散射,它在 shading 器内部局部且立即进行积分。光线也会立即被追踪,用于发射几何体采样的概率密度函数(PDF)评估(在4.1.2节讨论)。在这些情况下,仅追踪用户定义的场景子集,通常对应于单个网格,并且遍历一致性自然地从 shading 一致性中产生。
艺术家或制作管线组织场景的方式可能导致顶层层次结构构建效率低下,存在大量对象重叠。例如,整个岛屿的基础网格可能是一个单一场景对象,与岛上数以百万计的对象重叠。更糟糕的是,每种类型的实例化对象,例如每种植物,可能有一个可追踪对象,代表覆盖整个岛屿的实例集合。这些情况下的极端重叠破坏了 BVH 遍历的对数成本优势,可能使此类场景无法渲染。
为了避免顶层层次结构中的过度重叠,我们将大型对象(包括单个网格和实例集合)拆分为更小的部分。我们不是为每个部分创建单独的场景对象,而是在每个对象的内部 BVH 中创建入口点(entry points),并将这些入口点的引用插入顶层层次结构。该系统与最近的部分 BVH 重编技术(Benthin 等人2017)大体相似且是同时开发的,入口点与部分重编中的 BRefs 是可互换的术语。与部分重编非常相似,我们的入口点系统本质上是基于对象 BVH 的子树构建顶层 BVH,而不是直接基于对象包围盒。我们没有将入口点逻辑直接构建到顶层 BVH 构建器中,而是采用两步过程:首先构建对象 BVH,然后计算入口点,最后使用与对象 BVH 完全相同的 BVH 构建器在入口点上构建顶层 BVH。我们计算入口点的终止条件包含两个主要因素:候选入口点的类 SAH 启发式度量之和与候选父节点之和的比较,以及每个候选入口点相对于相机的立体角。
3.4 表面 shading
在遍历每个光线批次后,我们将产生的命中点按场景对象分组以进行 shading。重要的是,实例化对象的命中点被分组并当作单个对象进行 shading。我们进一步在每个对象内对命中点进行排序以实现 shading 一致性;对于网格,我们按面排序,为逐面 texture 提供最大一致性(Burley and Lacewell 2008)。
shading 器计算表面散射,将新的辐射度收集光线排入未来的光线批次。shading 器还将发射辐射度乘以路径吞吐量后添加到帧缓冲区。按照标准做法,散射光线使用多重重要性采样生成,以结合 BSDF 和光源采样技术(Veach 1997)。然而,与传统的下一事件估计中仅追踪透射率光线不同,所有散射光线都收集辐射度。不过,最近我们不再允许通过光源采样生成的光线收集间接辐射度,原因在4.5节中讨论。
任何特定的 shading 器都可能被绑定到多个对象上。为了实现这些对象的异步 shading,我们为每个对象创建 shading 器的本地副本。本地副本允许 shading 器在 shading 过程中修改其状态,而无需锁定或其他同步的开销。这种机制还允许我们针对每个对象任意地改变 shading 器。例如,灯光师可以将对象修改器附加到各种场景对象上,以覆盖 shading 器参数,而无需创建和管理 shading 器的持久副本。并发线程优先为不同的对象 shading,但当没有其他对象可 shading 时,我们会为每个 shading 器创建额外的克隆,以允许多个线程为单个对象 shading。
我们的原型不需要 texture 缓存,因为我们通常有足够的 shading 一致性来分摊文件访问成本。然而,我们现在使用了一个,主要是为了限制网络 I/O 负载。texture 数据访问经常超过我们 6GB 的缓存大小,但 texture 查找通常占渲染时间的不到 5%,而 I/O 仅占其中的一小部分。
texture 过滤基于光线直径,即光线被解释为一个锥体的直径,其顶角基于散射 PDF(Amanatides 1984;Nguyen 2007)。
我们的 shading 器还会访问其他数据,例如逐顶点属性和点云。点云可用于任意目的,通常用于通过动画效果操纵 shading,但在每个 shading 点上都会访问的一种类型是用于灯光选择的重要性缓存,这在第 4.1.1 节中讨论。所有这些数据源都受益于我们排序 shading 所提供的一致性。除了提高数据一致性之外,排序 shading 还最大限度地减少了 shading 器克隆以及与 shading 对象之间的上下文切换相关的其他成本。
3.5 体积积分
在确定并排序表面命中点之后,但在对其进行 shading 之前,我们计算沿每条光线段的体积透射率、内散射和发射。内散射光线被排入未来的光线批次,并且与表面散射光线相同。
由于体积积分作为排序延迟 shading 的一部分进行,我们的体积数据也受益于增强的一致性。然而,由于与表面积分相关联,这种方法仅对少量反弹次数实用。我们在第 4.5 节中讨论了我们最近如何解决渲染任意数量体积反弹的需求。
4 生产驱动开发中的案例研究
在本节中,我们展示了 Hyperion 中由生产需求驱动的选定开发案例。
4.1 采样复杂光照环境
复杂的光照,无论是直接光照还是间接光照,都带来了各种挑战。很难预测在生产过程中会出现的特定光照场景,更难以设计和实现对所有场景都足够且自动稳健的系统。
《Big Hero 6》包含一个有数十万盏灯的城市、围绕小而亮的光源的折射球体、一间由透过窗板过滤的阳光照亮的卧室,以及一个尘土飞扬的仓库,可见的阳光透过小天窗射入。《Moana》包含了由熔岩照亮的大规模烟羽和由折射阳光照亮的洋底。
有时,我们很想为艺术家提供额外的采样控制,以便他们可以手动调整渲染器来处理特定场景。然而,这种方法可能适得其反。例如,在《Big Hero 6》中,我们提供了“窗口光采样器”,可以放置在室内空间的窗户中,以将光线引出并到达外部的光源。事实证明,这些采样器很难正确放置和调整,并且当与用于室外灯光的现有灯光采样器结合使用时,可能导致对这些灯光过度采样,而对室内灯光采样不足。我们发现,在可能的情况下,自动采样解决方案通常更可取。
4.1.1 缓存点。电影场景中包含大量光源并不罕见。《Big Hero 6》的特色是夜间城市场景,其中包含多达 50 万个小而亮的

图 2. 《Big Hero 6》中的场景包含从数百盏灯(顶部)到数千盏灯(中部)再到数十万盏灯(底部)的各种情况。我们的缓存点系统允许在所有这些场景中进行稳健且高效的光照采样。
灯光,包括方向性光源如路灯和汽车前灯,如图2所示。我们最初的方法是在每个 shading 点遍历每个灯光以构建用于灯光选择的概率分布,但在这种情况下变得慢得无法使用。
我们尝试了用于灯光选择的层次树数据结构,但由于某些边缘情况和多样的灯光类型,特别是那些具有狭窄、高度方向性 IES profiles 的灯光,发现难以使其有效。我们意识到,即使在有许多灯光的场景中,邻近 shading 点之间的光照变化也不足以需要为每个点生成全新的概率分布。我们探索了多种缓存和重用灯光选择信息的可能方法,最终设计并实现了一个我们称之为 cache points 的系统。
我们生成初始的100,000个 cache points,随机分布在各个场景物体的包围盒内,然后进行一次粗略渲染迭代,将 cache points 放置在路径顶点的随机子集上,并剪除那些落在先前点目标半径内的点。在后续渲染迭代中以类似方式添加额外的点。为了填充每个新的 cache point,我们遍历每个灯光,估计其对以该点为中心的六个定向平面以及一个全向接收器的潜在贡献。然后,对于这七个分布中的每一个,我们存储一个灯光列表,该列表刚好包含足以解释到达该点97%能量的灯光(每个分布限制为至少4个、最多256个灯光)(Shirley et al. 1996)。为了应对 cache points 之间光照的快速变化,我们将非常接近 cache point 的灯光放入一个单独的列表。我们还聚合每个 cache point 邻域的信息,使得在灯光采样期间只需要最近点查找。cache point 数据库的总大小通常只有几 MB。生成 cache points 的时间可以忽略不计,并且被加载和处理在 cache point 迭代期间命中的场景物体所需的时间所掩盖。
为了进一步改进采样,我们在每个 cache point 维护每个灯光的可见性估计,概念上类似于 Georgiev et al. (2012)的方法。我们跟踪指向每个灯光的样本数量,并将其与到达灯光并接收到贡献的样本数量进行比较。此信息随后用于减少对那些最初被认为重要但实际上没有贡献的灯光的采样。该系统显著降低了噪声,例如,在由通过小窗户进入的阳光照亮的室内场景中,否则大部分被遮挡的太阳会将样本从其他光源引开。
为了从 cache point 生成灯光样本,我们根据 shading 点处的表面法线混合多个特定方向的分布,结合附近的灯光和上述学习到的可见性信息,然后从得到的概率分布中选择一个灯光。未出现在分布中的灯光往往采样不足,并产生 fireflies,即孤立的异常明亮像素。我们使用 clamping 和 denoising(第5.1.2节)来限制 fireflies 的影响。
4.1.2 自发光几何体。Hyperion 的设计使得任何物体都可以成为光源。特别是,任何表面的自发光都可以由表达式和 texture 驱动。虽然我们最初直接采样了几种显式灯光类型,但我们没有办法先验地将一般物体识别为光源,确定其表面上的自发光分布,或者以除了通过 BSDF 样本偶然命中它们之外的任何方式对其进行采样。这因延迟加载而进一步复杂化——我们无法知道尚未加载的表面上的自发光分布。
然而,在《Moana》制作后期,我们遇到了一种情况,缺乏自发光几何体采样成为一个严重问题。电影中有一百个镜头出现了熔岩怪物 Te Ka,其自发光身体是原本黑暗环境中的主要光源(图3)。Te Ka 身体上集中而明亮的熔岩流照亮了弥漫场景的烟羽,更复杂的是,烟雾中还有闪电。为了收敛到可用的噪声水平,预计每帧平均需要450核心小时来渲染。
在此之前,我们从未迫切需求实现自发光几何体采样,但现在我们需要在短时间内提出一个解决方案。我们决定尝试将我们的自发光体积采样器重用于自发光表面,认为这将是一种直接且有效的方法。第一步是识别自发光物体,这很容易,因为自发光必须在每个 shading 器中显式启用。我们在渲染器启动时非延迟地加载这些物体,并对每个物体遍历其细分网格的每个三角形,在三角形中心评估自发光表达式,并将三角形及其功率存储在一个列表中。然后,对于每个物体,我们构建一个体积网格,将相关三角形的包围盒光栅化到其中,并使用该网格作为采样器。这种方法有效,但使其实用化证明很困难。更高的网格分辨率带来更好的采样,但非常消耗内存且采样速度慢。而且,由于网格结构不是时变的,移动的三角形在光栅化时占用过多空间并破坏了采样质量。我们需要一种不同的方法。

图3. 来自《Moana》的一个制作帧,需要自发光几何体采样,因为场景中的主要照明来源是由明亮熔岩构成的大型角色“Te Ka”。
我们决定尝试从头构建一个新的灯光采样器。这个灯光采样器将存储变形的自发光三角形本身并直接对其进行采样。像之前一样识别物体的自发光三角形后,我们将它们传入这个新的灯光采样器,在其上构建用于采样的概率分布,并构建一个时变 BVH 以进行高效的 PDF 评估。为每个 shading 点在三角形上构建视图依赖的概率分布对于除最简单网格之外的所有情况计算成本都太高,因此我们构建了一个仅基于三角形功率的固定概率分布,并使用 alias method(Vose 1991)在常数时间内从中抽取样本。我们最初担心基于功率的采样会导致样本分布不佳,但实际上它表现良好。基于三角形的方法是一项重大的实现工作,但最终产生了更清晰的代码,无需光栅化方法所需的启发式方法,并且对于带有运动模糊的动画网格,采样质量显著提高。
最终,改进的采样使我们能够以两倍于之前的速度渲染有问题的 Te Ka 序列,且噪声更少。对 denoising 的独立改进进一步缩短了渲染时间。总的来说,我们的自发光几何体采样在适当使用时已被证明非常有益,尽管在某些情况下,其好处确实需要与延迟加载的丧失以及为可能大量的三角形评估可能繁重的自发光表达式的开销进行权衡。到目前为止,我们仅为每个三角形网格构建一个灯光采样器,其中每个灯光采样器是该网格中所有三角形上的线性累积密度函数(CDF)。在实践中,我们尚未遇到大到需要空间上分割三角形列表并为每个网格构建多个 CDF 的情况,但如果需要这样做,我们设想使用第3.3节描述的 entry points 系统分割网格,并为所有 entry points 中给定 entry point 内的所有三角形构建线性 CDF,而不是在整个物体中。
4.1.3 路径简化。对于从相机开始的单向 path tracing 器要发现焦散路径,光线必须从漫反射表面散射,使其恰好从光滑表面反弹并击中一个小的明亮光源。在没有场景中间接光分布的先验知识的情况下,这一系列事件极不可能发生;因此,如果没有更复杂的技术,如双向 path tracing(Veach 1997),焦散无法被高效采样。随着导致最终镜面表面的表面交互变得更加漫反射,相机光线束变得不那么相干,并且仅使用 BSDF 采样持续到达光源的可能性降低。
在《Big Hero 6》的制作过程中,我们面临焦散导致 fireflies 散布在图像上的问题。在这些情况下,焦散图案本身在艺术上并不特别重要,因此我们没有投入大量资源来实现能够良好采样它们的光传输算法,而是试图以对图像整体影响尽可能小的方式消除焦散。我们测试的方法之一是 outlier rejection(DeCoro et al. 2010),但这需要大量内存,对于不同的 SPP 值产生不同的结果,并且在低 SPP 值下导致显著的能量损失。
我们意识到,如果最终表面更加漫反射,直接光采样将使到达光源的可能性更大,因此可以通过增加次级反弹中表面的粗糙度来允许有用的直接光采样,从而大大降低噪声(Kaplanyan and Dachsbacher 2013)。然而,我们不想消除所有间接镜面效果,因此我们设计了一种启发式方法,使粗糙度与光线直径成比例增加。光线变得越“宽”和越“漫反射”,我们就越会增加后续反弹的粗糙度,从而消除困难的焦散,而不会完全消除有趣的方向性光照效果,如 glossy–glossy 传输。
折射带来了另一个挑战。增加折射表面的粗糙度在消除噪声方面有效,但在某些情况下会极大地改变图像。例如,在阳光透过玻璃窗进入房间并投射出硬阴影的场景中,增加窗户的粗糙度会使阴影模糊,并极大地改变场景光照的特性。我们很快意识到,处理光滑折射的更好解决方案是直接穿过这些表面而不发生弯曲。为了产生良好的结果,我们调整了反射系数,使得直接穿过窗户的光线经历与原始弯曲对应光线相同量的前后表面反射,并且从折射物体(如水池)射出的光线不会发生全内反射,否则全内反射会阻止离开物体的光线覆盖整个半球。特别是,我们通过当非弯曲光线离开物体时,用相对折射率的乘法逆元替换它来实现这些特性。
路径简化(Path simplification)是我们对这一系列功能的称呼,这些功能会在后续反弹中修改 BSDF 属性,以消除难以处理的焦散(caustics),从而减少噪点。除非我们想要渲染一张“真实参考”图像用于对照或调试,否则路径简化始终处于启用状态。
4.2 《疯狂动物城》(Zootopia)中的毛发渲染
我们知道《疯狂动物城》需要一个充满迷人动物的城市,其外观设计要匹配现实中的对应物种,而制作如此多样的角色(最终有64个不同物种的157个独特角色)是一项艰巨的挑战。我们之前的 shading 模型(Marschner et al. 2003; Zinke et al. 2008)易于控制,但缺乏能量守恒。这对《超能陆战队》(Big Hero 6)来说已经足够,因为其中大多数角色都是深色毛发,但《疯狂动物城》中有多个近乎白色毛发的角色,而我们的多重散射近似(Zinke et al. 2008)使毛发看起来又暗又脏。此外,该 shading 模型本质上是一个人类头发模型,无法区分《疯狂动物城》所需的各种物种。
除了制作和 shading 方面的挑战,《疯狂动物城》在毛发的几何规模上也带来了挑战,既包括存储几何体所需的内存,也包括遍历如此多曲线所需的渲染时间。一个镜头中最多有5000个角色,典型角色有200万到1000万根毛发,平均每根毛发有9个曲线段,而对于毛发特别长或卷曲的角色(如绵羊),每根曲线可多达100个段(示例见图4)。
4.2.1 shading。我们从 d’Eon et al. (2011)的能量守恒头发 shading 模型开始,但使用了近场公式来避免在纤维宽度上进行昂贵的数值积分。我们发现,使用该模型进行暴力多重散射能带来我们想要的柔和与丰富感,而额外的方位角粗糙度控制则提供了物种区分度,但我们还需要进一步提高效率和可控性。通过使用一种新颖的第四瓣(fourth lobe)和闭合形式的逻辑斯蒂方位角分布(logistic azimuthal distribution),我们获得了足够的效率,使暴力多重散射变得实用。在可控性方面,我们通过反转数值散射模拟的结果,从艺术家指定的多重散射颜色推导出单次散射参数。我们的最终模型具有六个直观参数(Chiang et al. 2016a),此后已用于我们制作中的所有动物和人类角色。
4.2.2 几何与遍历。我们将毛发纤维表示为三次 B 样条曲线(cubic B-spline curves),其宽度沿曲线长度变化。与预细分曲线相比,样条曲线内存效率高,且在任何缩放级别下都能提供高质量。与常用的贝塞尔表示(Nakamaru and Ohno 2002; Woop et al. 2014)不同,后者每个段需要四个控制顶点(CV),而 B 样条表示在初始段之后,每增加一个段只需一个控制顶点。为了进一步减少曲线内存,我们将控制点位置量化为相对于包含该组曲线的包围盒的16位定点数。我们将曲线段存储在一个 BVH 中,这甚至可能比存储控制点更消耗内存。为解决这个问题,我们按照 Mahovsky (2005)的描述,将包围盒位置量化为相对于其父包围盒的8位定点数。

图4. 《疯狂动物城》中各种包含毛发的场景:需要精确多重散射的高反照率毛发(上),使用我们直观颜色参数化的具有复杂颜色变化的角色(中),以及包含大量毛茸茸角色、需要高效几何表示和高效遍历的群体(下)。
对于光线与曲线段的求交,我们遵循 Nakamaru and Ohno (2002)的方法,将每个曲线段投影到垂直于光线的平面上,递归地二分该段直到达到误差容限,然后进行线性段求交。在求交时,我们将3D B 样条段转换为光线求交平面内的2D 三次多项式形式。三次多项式形式允许更高效的位置和导数计算,避免了重复计算 B 样条或贝塞尔基函数的需要。我们没有使用根据指定误差容限预先计算的固定递归深度(Nakamaru and Ohno 2002),因为这可能导致即使对于远处的曲线也会产生任意高的递归次数,而是在每个遍历步骤中测量误差,并与光线直径进行比较。我们将此误差估计为每个切向量与线性段近似之间差值的总和。近乎笔直的段、远离相机的段或与宽直径间接光线相交的段只需极少的递归。在我们典型的制作场景中,我们发现绝大多数光线与曲线段的求交在使用我们的误差度量时不需要递归。
众所周知,密集、对角排列的曲线集可能由于段包围盒重叠而表现不佳(Woop et al. 2014)。我们的方法是自动分割长曲线段,将每个子段分别添加到 BVH 中。虽然这对长而细的曲线段效果很好,但对短而粗的曲线段没有帮助,因为分割只会加剧重叠;艺术家只需避免这种情况。例如,当艺术家为了渲染效率而降低远处曲线的密度,并通过增加曲线宽度来补偿时,他们也会小心地降低沿曲线的控制顶点密度,以保持曲线段的长宽比。

图5. 《海洋奇缘》(Moana)中不同类型的水:带有船尾迹的海洋(上),带有开阔海洋和角色互动的海岸线(中),以及艺术指导下的有感知的水(下)。
4.3 《海洋奇缘》中的海洋渲染
《海洋奇缘》包含了我们工作室迄今为止制作过的最大、最复杂的水体场景。几乎每个镜头中都有水,包括广阔的海洋、船尾迹、飞溅、海岸线、水墙以及高度艺术指导的有感知的水(见图5)。在《海洋奇缘》制作期间,开发了一套专用管线(Garcia et al. 2016),用于生成单一的大型水体网格,该网格由水平集合成图(Palmer et al. 2017)生成,该图可包含任意数量的输入,例如程序化海洋表面或体素化水平集。
在这个系统中,网格分辨率由相机视锥体定义,屏幕外的几何体保持低分辨率,导致网格平均大小约为2 GB。这种方法避免了将不同类型的水作为独立元素处理。例如,地平线处数英里外的海洋和近处的飞溅或气泡是同一个网格。由于水体表面采用水平集定义,生成的几何体始终是水密的,并可用作定义海洋水体散射光学属性的均匀体积的边界。水体的体积外观通过物理正确的散射参数进行完全 path tracing。
我们本打算将泡沫纳入水体渲染设置中,以便在清澈的水、浑浊的充满气泡的水和泡沫之间无缝混合,但交付生产就绪系统所需的研究和开发耗时太长。因此,泡沫使用标准体积和粒子作为独立元素进行建模。
4.3.1 photon mapping 焦散。穿过清澈水体的折射焦散是热带海岸线水体外观的一个标志性特征,当波浪翻涌时,会在水下的沙地上形成复杂的图案(见图5,中)。此外,反射焦散会在海岸线岩石和其他附近物体(如开阔海洋上的船只)上产生微妙的照明。以逼真的方式将这些光照效果融入镜头中,是定义水体外观和增加视觉复杂性的关键。
在像 Hyperion 这样的纯正向 path tracing 器中,渲染焦散效率极低,且无法在合理时间内收敛。虽然某些双向技术可以解决这类困难特征,但我们不能仅仅为了渲染焦散而改变 Hyperion 流式架构固有的单向特性。投影方法被认为过于劳动密集,难以在大量困难镜头中做好。为了实现逼真的焦散,我们实现了一个有限的 photon mapping(Jensen 1996)子系统,它仅渲染理想的镜面焦散,且仅与水面交互进行反射和折射。
在许多情况下,光子图需要覆盖大面积区域,例如海岸线或水下镜头中浅海海底的大片区域。我们通过自适应分布光子来解决这一问题。我们首先在场景中均匀分布一组光子。然后,在分布缓存点的同一初始迭代中,我们收集这些光子,但不是将它们的贡献写入图像,而是将它们的贡献记录到它们发射平面上的一个网格中。该网格随后用于在该平面上构建概率质量函数(PMF),并在每次渲染迭代前用于分布一组新的光子。该系统自动导致在相机视锥体内、靠近相机处以及物体可见部分的光子密度更高,如图 6 所示。这种方法目前仅针对窄的、无限远的光源实现——由于发射方向大致平行,在发射平面上构建空间 PMF 就足够了。然而,将这种方法扩展到漫发射的有限光源也应该是可行的。为了完全通用,可以在主样本空间中构建 PMF,而不是在平面上构建。
我们的光子系统不支持体积焦散,这些焦散改用 cucoloris 灯光在海洋体积内散射来建模。
虽然该系统除了镜面水面焦散和类似效果外,能力有限,但它基本上是自动化的,并用于几乎所有包含海岸线和船只的镜头。大量包含水的镜头证明了为此专门目的开发一个完整子系统的合理性。有限的范围使我们能够针对《海洋奇缘》中的专门用例进行优化。后来对该系统的扩展,部分支持了区域光,也让艺术家在《雪宝的冰雪大冒险》中找到了对冰焦散的有限应用。

(a) 均匀光子分布

(b) 自适应光子分布

- 场景上下文

- 概率质量函数
图 6. 自适应光子分布示例。(a) 和 (b) 分别展示了在大型环境中使用相同数量光子、未使用和使用自适应光子分布渲染的一块小岩石的特写。特写的上下文在 (c) 中用红色圆圈标出岩石,用于自适应光子分布的概率质量函数在 (d) 中显示,方形水面、相机视锥体、相机周围区域、岩石以及岩石后方区域都清晰可见。
4.3.2 光晕灯光。渲染水的一个挑战是,物理正确的太阳会产生非常强烈、刺眼的闪烁高光,在许多情况下不仅噪点多,而且不符合电影所需的视觉效果。均匀增加水面 shading 器的粗糙度会模糊掉这些特征,并不是令人满意的解决方案。取而代之的是,通过对太阳周围的光晕提供艺术控制来柔化阳光,模拟太阳圆盘周围的米氏散射光晕。
遵循我们简单的范式,我们没有通过表达式提供对光晕的完全控制,而是设计了一个双参数模型来确定光晕的形状。该模型的一个重要属性是整体光强度恒定,避免在调整参数时发生任何强度变化。虽然光晕灯光是专门为解决水的视觉效果而开发的,但它也进入了灯光师的标准工具集,用于定义高光、阴影终止线和阴影边界的形状和颜色,如图 7 所示。
4.4 统一次表面散射,从雪到皮肤
对于《超能陆战队》,我们使用归一化扩散(Burley 2015)作为次表面散射解决方案。它与蒙特卡洛参考匹配良好,且高效、易于控制。然而,与其他扩散近似一样,它受到半无限平板假设引起的伪影影响。这类伪影在《冰雪奇缘:生日惊喜》中尤为成问题,其中雪怪 Marshmallow 由几何复杂的相互穿插的冰和雪构成,在薄区域表现出不希望的变暗,以及过多的光线渗入缝隙。此前,在《冰雪奇缘》中使用 Reyes 渲染时,这种冰雪整合是通过劳动密集的临时方案完成的,结果并不完全令人满意,而且无论如何都不适用于 Hyperion。

- 无光晕

- 常规光晕

- 有色光晕
图 7. 一个简单场景,分别由常规太阳光(左)、带有用户自定义光晕的太阳光(中)以及带有有色光晕的太阳光(右)照亮。光晕有助于塑造高光、阴影截止线和阴影边界。

图 8. 来自《冰雪奇缘:生日惊喜》的一个制作帧,其中的角色使用了 path tracing 的次表面散射雪。
4.4.1 path tracing 雪。对于《冰雪奇缘:生日惊喜》,我们为雪实现了一种体积 path tracing 方案,该方案与冰无缝结合,并避免了艺术家之前苦苦挣扎的瑕疵。为了使 path tracing 雪在制作渲染中可行,如图 8 所示,我们做了一些简化。我们将雪视为完全均匀的体积,具有单色散射。为了渲染效率,我们假设折射率匹配的漫透射界面。此外,由于雪通常具有均匀的光学特性,尽管不太直观,我们让艺术家直接使用体积单次散射参数来控制雪。
虽然在较小规模上取得了成功,但 path tracing 次表面散射忠实地保留了所有几何细节这一事实,在渲染《雪宝的冰雪大冒险》中更大的雪景时带来了令人惊讶的挑战。例如,树木周围的雪裙通常不封闭并悬浮在地面上,而屋顶等其他表面上的雪块相互穿插,产生了不想要的阴影。为了解决几何问题,我们实现了多物体界面计数,以确定何时处于雪体积内部,以及一种探测射线启发式方法,试图处理开放和透明表面,但最终艺术家需要更加注意几何正确性。

- 折射率 1

- 折射率 1.4
图 9. 斯坦福龙在 (a) 中以折射率 1 渲染,由于缺乏内部反射,显示出过亮的薄边缘。可以通过使用更合理的折射率值来修复,本例中 (b) 为 1.4。龙模型由斯坦福计算机图形学实验室提供。
我们还面临与散射参数合理性相关的挑战。在动画电影中,通常希望并实现夸张的光线渗入阴影,这通过较高的散射距离来实现。然而,与扩散不同,这与 path tracing 次表面散射准确表现物体厚度的事实相冲突。例如,在《雪宝的冰雪大冒险》中,覆盖屋顶的雪层最初显得过暗,因为太多光线穿透到了深色屋顶。在这些情况下,我们依靠艺术家使用绘制的遮罩来减少显得过薄区域的体积散射。
计算效率是另一个挑战。在雪中使用合理的高反照率(即非常接近 1)进行 path tracing 次表面散射,需要模拟非常多的散射事件,这可能令人望而却步。我们发现,使用 shell transport(Müller 等人 2016)在雪体积内部采取更大的步长,可以使渲染如此高的反照率变得可行,尽管在实践中,我们的制作发现使用略微降低的雪反照率值并结合更高的散射距离就足够了。
4.4.2 path tracing 皮肤。随着 path tracing 雪的成功,我们想知道是否能为其他材质(如皮肤)获得类似的好处。第一个挑战是皮肤并非均匀的,并且让艺术家直接指定单次散射参数并不直观。与之前的 Normalized Diffusion 一样,我们的艺术家绘制皮肤反照率贴图。类似于我们的毛发颜色重参数化,我们从 Normalized Diffusion 参数化中推导出单次散射参数。自我们最初的实现(Chiang 等人 2016b)以来,我们发现假设内部散射的折射率匹配界面会导致薄边缘过亮,因为缺乏内部反射,如图 9 所示。然而,随着内部反射的引入,平均路径长度增加,体积吸收量也增加,使得我们的重参数化依赖于折射率(IOR)。我们发现假设折射率为

图 10. 来自《无敌破坏王2:大闹互联网》的一个制作渲染,其中的角色使用了 path tracing 的次表面散射皮肤。
1.4(仅用于计算内部反射的能量比例)能合理地代表大多数材质,因此我们为此假设重新推导了单次散射参数:
其中,艺术家指定的表面颜色 A 和散射距离 d 在内部被转换为单次散射反照率 α 和消光系数 σt 以用于渲染。
理想情况下,精确的皮肤模型应该是分层且非均匀的,但为了艺术可控性,我们继续采用广泛使用的非物理方法,将皮肤建模为空间变化的均匀体积(Jensen et al. 2001)。以这种方式对皮肤进行彩色散射建模会产生过多的 shading noise,而动画电影中高度饱和的色彩溢出往往被夸大,这加剧了这一问题。我们通过按每个颜色通道的单次散射反照率比例进行采样来最小化这种 shading noise(Chiang et al. 2016b),并且我们发现由此产生的渲染效率与扩散出奇地相似。
通过匹配我们的归一化扩散参数化,我们能够重新渲染现有角色,艺术家们普遍更喜欢 path tracing 的结果,因为它增强了通常被扩散模糊掉的细节。然而,为了规避扩散的伪影和局限性,角色被建模为具有夸张的褶皱和皱纹,并使用了手绘的散射遮罩。因此,现有的制作继续使用扩散,但 path tracing 的次表面散射现在已用于所有当前制作中的所有材质,从雪到皮肤(见图10)。
4.5 渲染云景
在《超能陆战队》期间开发的体积渲染系统采用了排序延迟的理念,通过使用分裂并向 Hyperion 的批处理系统提供散射光线,而不是在散射时立即重定向入射光线。当遇到表面交点时,在 shading 之前,Hyperion 使用残差比率跟踪(Novák et al. 2014)估计透射率,并构建用于采样散射距离的概率密度函数。该 PDF 的形式来源于透射率估计、体积消光以及从缓存点收集的注量估计。在这些贡献之间执行多重重要性采样。图11(左)展示了分裂和 PDF 构建。该方法的更详细描述可以在 Fong 等人(2017)的课程笔记中找到。从缓存点生成的注量估计对采样的影响类似于灯光的等角重要性采样(Kulla 和 Fajardo 2012):在预期有较大内散射贡献的地方,PDF 较大。虽然从缓存点生成注量估计比等角重要性采样更灵活,但由于需要搜索最近的缓存点,其成本也更高。
为了分摊与昂贵的 PDF 构建相关的计算成本,PDF 被多次采样,并采用分裂来生成多条内散射光线,这些光线被排入光线批处理系统。
通过使用较大的分裂因子,该策略在渲染低阶散射时效率很高,以每个样本的高成本产生高质量的估计。不幸的是,对于高阶散射,例如在云和其他高反照率体积中,递归调用变得过于昂贵。
4.5.1 基于跟踪的体积。虽然高阶散射可以通过各种技巧近似,但我们发现,只有积分所有高阶散射,多达数百甚至数千次反弹,才能实现一致且逼真的云外观。
为了实现高阶散射,我们决定使用更轻量级的跟踪算法,这些算法不像之前的体积系统那样显式构建 PDF。在跟踪方法中,光线在体积内部散射并改变方向,而不是被完全追踪到下一个表面交点并沿途生成子光线(见图11)。对于直接照明和透射率,得到的估计质量远低于之前的策略,但成本也低得多,因此允许计算更多的反弹。两种策略差异的更详细描述见 Fong 等人(2017)。
标准的 delta 跟踪作为一种单色估计器,限制了我们使用彩色体积。在我们最近的出版物(Kutz et al. 2017)中,我们引入了一种光谱跟踪算法,消除了 delta 跟踪仅限于单色消光的限制,以及一种分解跟踪算法,该算法以更少的体积查找提供与 delta 跟踪相同的采样质量。利用我们新跟踪算法背后的数学框架(Galtier et al. 2013),我们还能够扩展我们的跟踪器,以在每条光线的多个点收集非均匀体积发射——通过将吸收/发射概率设置为1,无论散射和空碰撞概率如何,我们都可以在所有碰撞位置收集发射。为了执行空空间检测并为跟踪提供体积参数边界,我们使用基于 Yue 等人(2011)的分区度量自适应构建的八叉树。

- 旧系统

- 新系统
图11. 在我们的旧体积系统(左)中,在对表面交点进行 shading 之前,沿光线段构建一个详细的 PDF(蓝色),编码了透射率、消光以及从缓存点生成的注量估计。内散射样本被抽取并排入未来的光线批次。在我们的新体积系统(右)中,光线进入体积并仅基于体积的局部散射属性多次散射。阴影光线(虚线)与下一事件估计结合使用,以重要性采样直接照明贡献,并仅在完全离开体积后排入未来的光线批次。
4.5.2 相似性关系。作为高度前向散射的介质,云带来了严峻的性能挑战。各向异性散射分布增加了噪声,需要更多样本才能充分收敛,而短的散射距离需要追踪更多的光线。
体积参数的变换若产生相似的辐射分布,则被称为相似关系(或有时称为相似理论),并允许在保持大尺度外观不变的情况下改变体积参数。对于高阶散射,我们希望将高度各向异性散射向更各向同性的散射方向约简。散射系数 、相函数平均余弦 g、约化散射系数 和约化平均余弦 之间的一阶关系由 van de Hulst (1974) 推导得出:
使用约化散射系数和平均余弦通过增加散射距离和减少总反弹次数显著改善了渲染时间,并且通过使直接光照采样更有效而显著降低了噪声。我们发现,基于反弹深度在各向异性与各向同性散射之间进行平滑插值,在提高效率与准确再现重要光学效果之间提供了良好的平衡。具体而言,我们当前在第 5 次到第 20 次反弹之间将 从 g 线性插值到零,然后利用前述关系求解 。我们的追踪器所使用的特定空间区域内消光系数的下界和上界也需要适当插值。
4.5.3 无路径分裂的光照采样。在我们之前的体积系统中,路径在每个散射事件处被分裂,以结合光照采样和相函数采样技术。与我们的表面散射一样,每条散射光线被允许继-
续路径,平等地收集直接和间接辐射。虽然这种策略对于低反照率体积的表面-表面和表面-体积交互效果良好,但在高反照率体积中可能产生无界的路径树。为防止这种情况,我们需要积极的 Russian roulette 以及独立控制的体积反弹限制,以防止光线爆炸。
在新的体积系统中,为了实现高反照率体积的无界路径长度积分,我们消除了路径分裂。取而代之的是,通过光照采样生成的光线不再被允许在体积中或从表面发生进一步散射。
在被分派到光线批处理系统之前,光照采样光线首先立即穿越体积以计算透射率,并使用 Russian roulette 来防止在稠密体积中此类光线使批处理系统不堪重负。当表面可能穿透体积时,会执行即时表面遍历以限制穿过体积的积分距离。表面 shading 仍像以前一样通过批处理系统延迟处理。图11概述了两种体积积分策略的差异,图12展示了使用两种体积系统对同一云层进行等时渲染的结果。
5 使 path tracing 在生产中实用化
在本节中,我们讨论如何处理、排查问题以及艺术指导渲染图像。
5.1 处理 Monte Carlo noise
残余 noise 是像 Hyperion 这样的 Monte Carlo renderer 中的一个基本问题。我们使用多种技术来应对 noise:通过允许我们降低 SPP 来改善视觉质量或节省渲染时间。
5.1.1 自适应采样。Monte Carlo 渲染中的 noise 分布不均匀,因为光线路径和材质在图像上变化。以恒定的 SPP 渲染整个图像会在 noise 较少的区域浪费样本。理想情况下,我们希望每个像素使用该像素所需的最小 SPP。

- 旧系统

- 新系统
图12. 使用我们旧版《超能陆战队》时代的体积渲染系统(左)和新的基于追踪器的系统(右)渲染的云层的等时比较。旧系统限制为254次反弹(对于高反照率体积而言是较低阶散射),但仍产生比新系统明显更多噪声的图像。新系统产生的图像噪声更少,同时支持高效的高阶多重散射。
Hyperion 的自适应采样器将请求的 SPP 解释为总体样本预算,而非每像素的最大值。在每次迭代开始时,样本按像素方差的比例分配给每个像素(参见第5.1.6节)。方差估计首先被模糊,因为估计值有噪声,并且靠近高方差、难以采样的像素的像素,即使其方差较低,也可能同样难以采样。由于运动模糊图像中的方差倾向于沿运动方向拖尾,此模糊使用基于方差图像结构张量的各向异性核。
我们遇到了几个自适应采样挑战:
—萤火虫:为防止自适应采样器向萤火虫发送过多样本而导致图像其余部分受损,我们钳制方差估计,并且方差以低于线性的速率驱动样本数量(尽管这可能限制自适应性)。
—遮罩渲染通道:这些渲染通道输出遮罩和几何信息,而不渲染颜色。由于渲染颜色中的噪声无法引导自适应采样器,它使用遮罩本身的方差。
—被排除对象的样本预算:艺术家通常将场景划分为单独的渲染通道,例如角色通道和环境通道(参见第5.3.4节),其中被排除或“保留”的对象在摄像机命中时渲染为黑色。理想情况下,将对象分离到不同通道不应显著影响场景的总体样本预算,因为保留对象应需要最少的样本。为实现这一点,Hyperion 的自适应采样器使用收敛阈值来检测此类像素,一旦像素被认为已收敛,其剩余的 SPP 将从渲染进程的样本预算中移除。这是一个保守的阈值,大多数像素永远不会达到,仅旨在防止因保留对象导致的样本预算膨胀。
—渲染通道间的 Alpha 不一致性:单独的渲染通道仅通过将其颜色相加来合成
和 alpha。自适应采样可能导致每个通道中同一像素使用不同的 SPP 数量,从而导致不同的 alpha 采样。这可能导致合成瑕疵,例如几何体边缘的泄漏,因为 alpha 值之和并不精确为1。我们通过一致 alpha 功能解决此问题,该功能对颜色应用自适应采样,但对每个像素和渲染通道使用相同数量的样本渲染 alpha。
— 亚像素对象:孤立的亚像素对象(如尘埃粒子)可能会被完全遗漏,如果收敛阈值在对象首次被命中之前就认为包含它的像素“已完成”。
—使采样适应降噪:我们计划将降噪集成到自适应采样器中,类似于 Rousselle 等人(2012)的方法。这将通过降噪器对降噪后方差的估计来驱动自适应采样,从而在降噪效果好的区域节省渲染时间,尽管这确实要求渲染器在每次迭代后运行降噪器。
—迭代次数限制自适应性:自适应采样器仅在迭代结束时更新样本分配,因此无法完全均衡噪声水平(例如,128 SPP 的渲染只有三次适应机会——在16 SPP、32 SPP 和64 SPP 之后)。减小迭代规模将允许更多的自适应性,但更小的迭代效率会更低(参见第6.2节)。
—局部 SPP 控制:用户建议添加用户指定的每对象 SPP 控制,但这与我们追求简单而非灵活性的理念相悖。当出现噪声问题时,我们更倾向于调查根本原因(例如,特定 shading 器中重要性采样不佳)或更广泛地解决问题(例如,自适应采样)。
—渲染后合成调整:合成中的曝光调整(第5.3.8节)会改变图像不同部分噪声的可见性,因此自适应采样器追求空间均匀噪声水平的目标并非最优。因此,我们不鼓励进行极端的合成时曝光调整。
5.1.2 降噪。当我们决定为《超能陆战队》采用 Monte Carlo 渲染和 Hyperion 时,一个主要担忧是漫长的渲染时间。如果没有渲染后 denoising,按时完成电影渲染将是不可能的。
我们的降噪器受到 Li 等人(2012)和 Rousselle 等人(2013)工作的启发。参见图13中来自《海洋奇缘》的示例。它使用空间变化核对渲染图像进行空间和时间滤波,试图平滑噪声而不模糊图像细节。
Hyperion 写入且降噪器读取一个“特征”图像,其中包含以下层:
—漫反射与镜面反射:将渲染颜色分解为独立的“镜面反射”和“漫反射”部分;辐射贡献按照相机光线首次击中的表面其漫反射与镜面反射波瓣的相对强度,按比例分配到漫反射和镜面反射帧缓冲中。
— Albedo:表面颜色(含 texture)
—表面法线方向
—深度
—前向与后向运动矢量
—漫反射、镜面反射、albedo、表面法线和深度的方差(见第5.1.6节)
为了进行时序降噪,降噪器读取前一帧、当前帧和下一帧(要求降噪器在所有三帧渲染完成后运行)。降噪器利用运动矢量将前一帧和下一帧预变形到当前帧的位置。
降噪器对邻近像素和相邻帧进行加权平均,每个像素使用不同的非对称核。权重根据颜色和特征的相似性从邻近像素中提取。相似性的敏感度由相应的方差决定。
萤火虫具有极高的振幅,即使经过降噪也可能在图像上留下明亮的“污迹”。我们的降噪器将方差远高于邻域平均方差的像素检测为萤火虫。它完全移除这些萤火虫,用邻域数据替换它们。这实际上会导致能量损失(图像变暗),但比将能量保留为明亮污迹更可取。
我们最初的降噪器过度模糊了头发和毛发中的精细细节:降噪器以表面法线方向特征为线索,但对于像头发这样的细曲线(其法线在头发的亚像素直径范围内变化),该特征定义不明确。在《Big Hero 6》中,Hyperion 将“法线”特征写入零值;降噪器检测到这一点,并限制了对头发的滤波量,以防止模糊头发细节。由于该影片的角色大多为深色头发,这种方法效果尚可。
在《Frozen Fever》和《Zootopia》中,一些角色有金色头发和浅色毛发,细节更明显,噪声问题比深色头发更严重。降噪器最初要么保留过多噪声,要么过度模糊细节。我们修改了头发 shading 器,将头发的切线方向输出到特征图像的“法线”层。头发的切线方向定义明确,在像素内稳定,并且与图像中的可见特征高度相关。这使得降噪器能够有效滤波头发而不会过度模糊。
在《Moana》中,我们发现降噪器模糊了 Te Kā火山烟云中的细节,这些烟云是渲染的体积。问题在于体积缺乏通常为降噪器提供线索的几何特征:表面法线方向、表面颜色和深度。我们通过让体积渲染器根据体积的梯度计算法线来解决这个问题。这对于像烟云这样密集且细节丰富的体积特别有用。
降噪器用于大多数制作镜头,除非禁用,否则会自动运行。降噪器使艺术家能够以原本所需每像素采样数的1/4到1/8进行渲染,从而节省大量计算时间并加快周转。
5.1.3 手动渲染内技术。为了合成灵活性,艺术家通常将场景拆分为针对不同元素类别(例如角色与环境)的独立渲染通道。这也使灯光师能够为每个渲染通道选择最佳的 SPP,而不是对所有元素使用最差情况的 SPP。
当某个特定灯光引起噪声时,艺术家可能会将该灯光分离到单独的渲染通道中。由于没有其他灯光抽取灯光样本,该通道通常渲染噪声更少;所有灯光样本都针对有问题的灯光。Hyperion 的发射类别渲染输出(第5.3.5节)使得判断噪声是否由特定灯光引起变得容易。
5.1.4 手动后期渲染技术。当某个元素在多个帧中看起来相同时,灯光师可以以高 SPP 渲染单个源帧,并在合成中将该保持帧用于多个目标帧。
重投影是保持帧的泛化;即使元素或摄像机在移动,它也会将单个高 SPP 源帧复用于多个目标帧。合成利用目标帧的摄像机变换和几何体,将源帧重投影到该目标帧的元素表面上。当某个表面在目标帧中可见但在源帧中不可见时,合成会输出一个条状渲染遮罩,Hyperion 使用该遮罩仅渲染请求的像素。
在运动有限的场景中,我们有时会在合成中进行运动感知的多帧平均,必要时进行条状渲染以填充小范围的去遮挡区域。
灯光师有时会在合成中应用散焦模糊和运动模糊,从而在渲染场景中关闭这些效果并避免相关噪声。
5.1.5 滤波器重要性采样。Hyperion 的早期版本使用经典的图像重建滤波器,将每个样本散布到帧缓冲区的 3×3 像素区域(按滤波器加权)。这导致一个样本的噪声或萤火虫会影响多个像素,使 denoising 和萤火虫移除变得困难。由于相邻像素间的噪声相关,这也使方差估计更加困难。
我们通过滤波器重要性采样(FIS)(Ernst et al. 2006)解决了这些问题。我们将每个样本仅散布到一个像素,对所有样本等权重,并以与重建滤波器权重成比例的概率选择相对于像素中心的样本位置。

- 原始渲染图像

- denoising 后的渲染图像
图 13. 我们的 denoising 流程以未收敛的渲染结果(左,来自 Moana)和多个特征缓冲区作为输入,生成具有最少伪影和过度平滑的最终质量图像(右)。在此示例中,输入的未收敛图像以 128 SPP 渲染。
使用 FIS 后,像素间的噪声不相关,表现为更高频的“椒盐”噪声而非“模糊”噪声。Ernst 声称 FIS 能减少噪声,因为样本不再具有隐式的重建权重,而光照和表面采样系统对此并不知情。
5.1.6 方差估计。Hyperion 估计每个像素渲染颜色及其漫反射和镜面反射分量的方差,以驱动自适应采样、引导 denoising 器并向用户报告 MSE 统计信息。朴素方法是计算单个样本对像素贡献的方差。但在 Hyperion 中计算样本方差会很困难,因为单个摄像机样本的多次反弹会在不同时间散布到帧缓冲区——我们永远无法获得单个摄像机样本的总贡献。使用样本方差还会使方差估计产生偏差,因为低差异样本是相关的而非独立样本(Rousselle et al. 2012)。
为避免这些困难,Hyperion 使用“双缓冲区”方法估计渲染颜色方差(Dmitriev and Seidel 2004; Rousselle et al. 2012)。Hyperion 为颜色(以及镜面反射和漫反射)配备了一对“半样本”帧缓冲区。摄像机样本以随机打乱的顺序分配到其中一个缓冲区。我们通过为每个缓冲区生成独立的缓存点,防止缓存点将相关噪声耦合到两个缓冲区中。在每次迭代结束时,我们根据两个缓冲区的差异估计每个像素的方差。该估计值含有噪声,因此自适应采样器和 denoising 器会对其进行空间滤波。
除了漫反射和镜面反射渲染颜色的方差外,denoising 器还需要反照率、法线和深度特征的方差。这些通过简单的样本方差进行估计。这很容易融入我们的架构,因为这些特征的值在首次命中时已知;我们无需等待后续反弹的结果。
5.2 分析/理解渲染过程
虽然 path tracing 常被提及的优点之一是简单性,但一个完整的、功能齐全的制作渲染系统不可避免地会带来一定程度的复杂性。为了让艺术家和技术人员能够充分利用该软件,系统需要易于理解、用户友好,并尽可能透

图14. Hyperion 的统计查看器对渲染统计数据进行组织、格式化、排序和搜索。
尽可能接近父级。最常见的情况是,用户想知道处理器时间花在了哪里,什么在内存使用方面代价高昂,或者为什么渲染图像不符合他们的预期。
除了典型的渲染输出日志外,Hyperion 还提供了一个全面的统计报告系统。统计数据既可用于正在进行的渲染,也可在进程完成后使用,以 JSON 统计文件的形式以及作为 OpenEXR 图像中的元数据提供。
Hyperion 的交互式统计查看器(图14)是一个基于 JavaScript/Web 的渲染统计展示。它可以在 Hyperion 的交互式渲染查看器中使用,也可以作为一个独立程序,或者通过 Hyperion 的内部 Web 服务器或内联网 Web 服务器提供的网页来使用。
由于制作场景的规模,统计内容本身可能变得难以招架——“信息过载”很快就会出现。将统计信息分解并格式化为具有可排序列的类别,使得大量数据更易于消化。例如,查看场景对象表并按开销排序,无论是内存占用还是 shading 时间。一旦识别出特别昂贵的 shading 器,就可以启用实时性能分析,以更细的粒度识别热点。输出统计数据也可以被自动化流程使用——我们能够通过查找被极少量间接光线击中的表面,识别出对最终图像贡献微不足道的场景对象,作为剔除的候选对象。
其他有用的渲染分析工具包括路径检查器(也集成到我们的交互式查看器中)、诊断渲染输出和 shading 器,以及各种几何体导出选项。开发人员在调查来自艺术家的支持问题时,可能希望写出位移细分网格、缓存点或包围体层次结构,以便进行调试。
在可能的情况下,我们尝试将错误与场景对象和/或图像位置关联起来。在 shading 过程中,断言可以抛出异常,然后由自定义处理程序捕获,例如尝试对零长度向量进行归一化。然后,相应的像素会使用负值标记一个“X”。这使得标记可以轻松地从图像中移除,并除了按类型列出错误或警告之外,还提供了问题区域的显著视觉指示。
在错误和警告方面,Hyperion 的总体理念在开发过程中发生了转变。最初,源于输入场景的问题不仅被标记,而且以一种强制修复数据的方式处理。随着时间的推移,这种严格性更多地转向了弹性——系统试图利用给定的数据产生尽可能好的结果,同时仍然生成局部报告以鼓励用户修正场景数据。
5.3 基于物理的渲染器中的艺术控制
虽然 Hyperion 是一个强大的 path tracing 器,拥有一系列功能,使得创建美丽的照片级真实感图像成为一个直接的过程,但华特迪士尼动画工作室的艺术家们很少被要求仅仅做到这一点。电影的每一帧都是一件精心制作的艺术品,追求导演、艺术总监、制作设计师和灯光领导所描述的愿景。艺术家们不断面临挑战,要在有限的时间和有限的计算资源内实现明确的非物理目标。本节解释了艺术家如何使用渲染器内外的各种工具来实现艺术指导并高效地制作最终帧。
5.3.1 传输修改器和独占灯光。有时精确的 global illumination 可能无法达到所需的艺术效果。某些对象可能会向环境中反弹过多或过少的间接光。或者导演可能只针对一个元素给出意见,同时批准场景的其余照明。在这些和其他情况下,必须以局部方式改变光传输。
使用传输修改器,灯光师可以缩放场景中两个元素(对象或光源)或元素组之间的光传输。例如,艺术家可以定义一个传输修改器,将特定对象和灯光之间的能量减半。当光线击中对象时,渲染器通过将标签附加到出射光线来记录交互。如果来自对象的光线到达灯光,系统识别出存在关系,并将该光线的吞吐量减半。但如果光线击中其他任何东西,则忽略传输修改器。
传输修改器的一种变体可用于将灯光局部化到特定元素。标记为独占灯光的灯光仅对与该灯光有定义关系的对象产生贡献。例如,艺术家可能会添加一个专属于角色的轮廓光,因为即使没有物理依据,稍微背光的角色也有一定的吸引力,并且因为它有助于将角色与环境分开,将注意力集中在他们身上。全局灯光可以以类似的方式进行局部改变。例如,艺术家可能仅为角色加宽主光,以在角色上创建比环境更柔和的阴影。为此,艺术家可以使用传输修改器消除全局主光对角色影响,并添加一个专属于角色的加宽主光。
传输修改器是艺术家以非物理方式控制场景中光传输的强大工具,但也有局限性。如上所述,少数几个小对象组之间的控制很容易描述。然而,要控制许多大对象组之间的光传输,数据管理的负担开始增加,尤其是当需要复杂的包含/排除关系时。
5.3.2 区域渐变。与 Pixar 的 Rods(Hery 等人,2016)类似,我们允许艺术家在场景内体积渐变形状或区域内调整光照贡献。此外,我们的区域渐变可以在材质 shading 器表达式中以任意方式使用。例如,几何遮罩表达式可以引用区域渐变来切除表面的部分或全部,例如,让光线透过屏幕外对象的一个洞显示出来,或者可以调制表面反射的各个方面,例如减少镜面反射响应。因此,区域渐变在满足导演意见方面为艺术家提供了极大的灵活性和局部性。
为了提高渲染效率,区域渐变(region grads)被实现为 shading 的一部分,而不是作为体积效果。灯光 shading 器使用光线的起点来评估区域渐变,从而允许在受光表面上调制灯光的贡献,例如用于强调阴影。表面 shading 器使用表面命中点来评估区域渐变,其结果可用于材质 shading 的任何部分。
5.3.3 阴影塑形(Shadow Shaping)。灯光师通常希望对灯光和阴影进行非常具体的控制,以实现场景的艺术指导。他们制作自定义的 IES 配置文件(Illumination Engineering Society of North America 1991)来控制灯光的发射,并使用 cucoloris 图像在图像中塑造特定的灯光和阴影形状。根据他们试图实现的控制细节,这可能是一个非常耗费人力的过程,但经常被用来伪造场景中不存在的特定阴影,或者替换环境中以不吸引人的方式影响角色的阴影。请注意,替换阴影需要两个渲染通道(render passes),一个用于渲染投射不需要的阴影的物体,另一个则移除该物体,并将替换阴影投射到场景中的其他物体上。
对于 cucoloris 效果,艺术家可以简单地将所需的阴影形状放置在灯光路径中,就像在实际的聚光灯中一样,但除非聚光灯的光线完全聚焦(这从来都不是实际情况),否则该形状会被模糊掉。相反,我们的灯光 shading 器使用艺术家定义的投影将 cucoloris 图像投射到受光表面上,然后在每个表面点处将 cucoloris 乘入灯光的总体贡献中。虽然这不符合物理规律,但它为艺术家提供了所需的控制。
5.3.4 渲染通道(Render Passes)。即使使用了上述所有控制手段,Hyperion 直接执行生成的图像也很少是电影中使用的最终图像。艺术家将渲染过程的各种输出分离并重新组合,以在给定的时间内实现特定的艺术指导。
渲染通道是由艺术家生成的、针对图像不同组件的完全独立的渲染。例如,角色通常会被拆分到自己的通道中,但艺术家也可能拆分出特定的前景物体或他们知道在渲染后想要操作的物体。这样做有两个主要原因,并且几乎在每种情况下这两个因素都存在。渲染通道提供了对图像某些方面的艺术控制,并且还允许艺术家进行迭代,而无需每次都重新渲染整个帧。
在 global illumination 渲染器中,每个渲染通道仍然必须处理整个场景,以获得准确的间接光传输。这并不像看起来那样低效。例如,在角色通道中,环境被“遮罩掉”(matted out),在摄像机命中时渲染为黑色,仅对间接光照做出贡献。尽管每个通道仍有额外的开销,但计算完整 GI 的像素总数与没有遮罩的单通道渲染大致相同。
然而,在某些情况下,艺术家会故意从某些通道中排除物体,以进行控制或渲染管理。例如,一个特别重的体积通道可能会在单独的通道中以较低的分辨率或较少的光线反弹次数进行渲染,并从其他通道中省略以加快它们的速度,即使接受这些通道中通过体积的光传输效果可能不得不被伪造。
5.3.5 渲染输出与发射类别(Render Outputs and Emission Categories)。在单个渲染通道内,生成的图像有时很重要,但更常见的是,艺术家会识别出他们想要艺术性地组合的图像组件。例如,在渲染角色时,艺术家可能希望将头发与角色分开处理,使用从头发生成的遮罩(matte)。或者,他们可能希望将特定灯光组的贡献输出到单独的图像中,以便在渲染后进行重新平衡。
各种类型的渲染输出图像允许艺术家收集他们希望在合成最终图像时以创造性方式重新组合的构建块,所有这些都在一次运行中渲染完成。例如,每个灯光可以被分配一个发射类别(emission category),各个类别产生单独的渲染输出。
5.3.6 路径分类(Path Classifications)。例如,艺术家可能不仅想改变给定灯光集合对角色头发的影响,还可能想在其各种形式中调整该效果。来自该灯光集合的直接漫反射照明可能没问题,但镜面反射可能过于刺眼。或者直接
来自该灯光集合的照明可能没问题,但这些灯光从附近表面反弹到角色上的间接漫反射贡献可能太亮,或者饱和度不够。在这种情况下,路径分类允许将发射类别分解为其组成的光路类型。此外,路径分类可以应用于传输修改器(transport modifiers),以将修改局部化到光传输的一部分。
路径分类类似于“光路表达式”(light path expressions)(Heckbert 1990),但在关键方面有所不同。一组固定的路径分类——光源(light source)、直接镜面反射(direct specular)、间接镜面反射(indirect specular)、直接漫反射(direct diffuse)、间接漫反射(indirect diffuse)、焦散(caustic)和体积(volumetric)——为艺术家提供了一个简单、一致的界面,直接满足他们的需求。拥有一组固定的分类还允许高效实现,只需要在每条光线上使用几个比特来表示当前路径类型,并使用一个简单的状态机在每次散射事件时更新路径类型。重要的是,路径分类与一般的发射类别一样,在设计上是能量守恒的——因为这些分类是互斥的,并且每个灯光只能分配给一个发射类别,任何给定的光线只对一个渲染输出做出贡献。艺术家可以相信,如果他们将所有发射渲染输出加在一起,将得到与未分解图像相同的结果。
5.3.7 遮罩与深度遮罩(Mattes and Deep Mattes)。艺术家使用他们从渲染中生成的遮罩,以及他们使用合成引擎中的自定义工具从渲染结果中制作的遮罩。这为他们提供了进一步的灵活性,可以将渲染输出分解为更小的组件,以微调图像的某个特定部分。眼部遮罩非常常见,因为通常有大量的艺术指导来使面部,尤其是眼睛,具有吸引力。
深度遮罩提供了超越普通“平面”图像遮罩的额外灵活性。深度遮罩包含各种属性,如网格名称(mesh name)、元素名称(element name)、材质名称(material name)等,可以在合成时根据这些属性派生出各种平面图像遮罩。与更通用的深度输出图像不同,这些遮罩非常高效。它们使用低 SPP(每像素采样数)的实用通道生成,仅需要摄像机命中,并且每个像素内的样本被折叠到最小的唯一属性集。属性本身也存储为整数,使用与合成器中相同的哈希函数,以允许艺术家按名称选择。
5.3.8 综合运用(Putting it all Together)。渲染内工具如传输修改器(transport mods)和区域渐变(region grads)功能强大,但需要重新渲染才能进行调整,有时由于资源争用或进度压力,重新渲染可能是一个令人望而却步的要求。因此,艺术家倾向于过度生成渲染输出,以便在响应导演对其场景的说明时提供尽可能多的灵活性。最终的合成节点图将有数百个节点,重新组合从最终图像中拆分出的众多渲染通道的发射类别的路径分类,制作出在通常紧迫的日程下实现艺术目标的最终图像。每位艺术家都在这些数百张不同图像所能提供的艺术控制,与它们可能占用的千兆字节甚至太字节的磁盘空间以及在与最终合成图中如此多的大文件交互时可能导致的缓慢之间找到平衡。在一部电影的制作过程中,由于这种灵活性,必须进行积极的磁盘管理,以防止艺术家填满他们拥有的空间。图 15 所示图像的合成图的一部分见图 16。

- 原始渲染图像

- 最终帧
图15. 对渲染图像的艺术处理。基于物理的 path tracing 产生美丽的图像,艺术家进一步增强和修改这些图像以满足艺术指导需求。最终,物理准确性只是满足美学要求的重要起点。请注意,从原始渲染到最终帧,艺术家减少了小莫阿娜脸上的阳光高光,降低了水面泡沫的曝光度,带出了水面下的额外细节,并在背景中的远处悬崖上添加了雾气,等等。

图16. 仅图15中角色层的合成图,展示了艺术家用来组装最终帧的数十个渲染输出。
这种工作流程存在局限性。就像数字增加真实照片的亮度会揭示曝光不足区域的噪点一样,在重新组装过程中过度推动渲染输出会放大噪点或其他伪影。这通常表明应该修改场景并重新渲染,以生成更接近所需结果的内容。当进度压力或资源争用不允许这样做时,艺术家被迫将现有的渲染输出处理成可用的东西。有时最便捷的选择是直接在最终图像组合上绘制,并且有时这样做是唯一的选择,因为艺术家可能没有分离出他们需要的所有图层,或者渲染过程可能以某种微妙的方式出现问题,仅在最终帧中才被发现,而重新渲染又不可能。
在图15所示的镜头中,艺术家使用了本节讨论的许多技术来实现所需的艺术指导。正如在《海洋奇缘》中经常出现的情况,艺术家在合成中使用了单独的路径分类来调整水色和水面的反射率。在镜头的不同时刻,水面还将过多的光线反射到角色身上,这种反射光是一种令人不快的色调。虽然艺术家能够对猪 Pua 使用传输修改器,但对莫阿娜或图伊酋长效果不佳。当这些角色远离水面时,他们变得太暗,这意味着需要额外的灯光。艺术家添加了仅照亮角色的额外专用灯光,然后结合使用遮罩和 roto 来混合来自原始灯光和专用灯光的各种发射类别。这使他们能够在莫阿娜被从船上抱起时实现无缝的照明过渡。最后,背景悬崖是一个昂贵且噪点多的渲染,还有几条艺术指导说明。为了节省时间,艺术家只渲染了第一帧和最后一帧,并在合成中将这两帧的混合投影回几何体上。这使得艺术家能够使用遮罩和 roto 进行多处绘制修复和调整,而这些在单个渲染图像中很难实现。
尽管所有这些操作似乎与基于物理的渲染器的概念相悖,但我们的目标不是学术上的完美,而是制作出美丽、引人入胜且感觉真实的世界图像。
6 讨论与局限性
6.1 制作影响
Hyperion 通过提高艺术家效率、提升视觉质量和一致性,以及使我们的电影复杂性能够显著超越我们之前所能达到的水平,对我们的电影制作产生了重大影响。然而,仍然存在挑战。在完全由外部照明的室内实现艺术指导可能很困难。在艺术可控性与强烈的多次反弹间接照明所提供的视觉丰富性之间找到正确的权衡可能具有挑战性。Hyperion 可以渲染大量的几何体,因此我们的电影当然将其视为在屏幕上呈现更多几何复杂性的挑战。在进度压力下,渲染时间可能令人望而却步,需要额外的非渲染解决方案来满足艺术指导。某些形式的光传输,例如通过复杂体积,仍然代价高昂。
在最终帧的创建之外也存在挑战。Hyperion 是一个强大的诊断工具,提供了许多上游部门可以使用的见解。技术动画艺术家使用渲染来判断毛发穿透是否明显并需要修复。动画师可以在最终照明的背景下判断表演,以了解需要减少或强调什么。然而,这些用例是有代价的。计算资源非常宝贵(尤其是在截止日期压力下),因此为诊断目的启动渲染会带来带宽挑战,因为每个部门都在急于完成其工作。为了应对这种带宽限制,上游部门通常以较低的每像素采样数启动渲染。较低质量的渲染有助于缓解计算资源争用,但有时会让伪影溜过,而较高的每像素采样数渲染本可以显示这些伪影。因此,在计算时间与成功捕捉问题之间进行权衡,成为制作最后几个月的平衡行为。
总体而言,拥有一个强大的内部渲染器和一个致力于使其不断发展以应对新挑战的团队,取得了巨大的成功。对 Hyperion 实现的完全控制使我们能够提供有针对性的、深度集成的解决方案,并使我们能够灵活地快速响应出现的制作问题。
6.2 光线批次:交互性与吞吐量、批次饥饿和路径长度限制
当 Hyperion 拥有完整批次时,它能实现最高的吞吐量。每次迭代结束时总是包含一些部分填充的批次,其一致性相应降低。对于最终质量渲染,减小尺寸的批次问题较小,因为每次迭代中数百个批次中的几个低效批次几乎不可察觉。然而,为了在交互式会话中获得更即时的反馈,Hyperion 以渐进分数渲染第一次迭代,从少至4 SPP 和1/256的像素开始。在这个初始的交互式渐进过程中,批次远未填满。
此外,使用长路径渲染可能会在迭代结束时,当只剩下少数路径时,产生一连串几乎为空的批次。除了降低一致性之外,这样的小批次可能使系统缺乏足够的工作来保持所有核心忙碌。即使有完整批次,当系统在遍历和 shading 阶段之间来回切换时,由于需要同步,批次系统的核心利用率也会下降。由于这些原因,我们当前的架构对于典型场景在超过16个核心后扩展性减弱,并且不太可能利用未来计算平台预期的数百个核心。
为了解决这些问题,我们正在研究将遍历与 shading 重叠的方法,使用动态队列而非固定批次,和/或重叠迭代;近期的工作,如 Lee et al. (2017) 的工作,为更以队列为中心的架构提供了令人鼓舞的验证。
6.3 一致性遍历与核外效率
核外渲染从根本上是在光线求交带宽与从磁盘访问数据之间进行权衡;由于从磁盘访问数据本质上比访问内存或缓存中的数据慢,因此必须通过增加每次核外数据访问可处理的光线数量并减少所需的核外数据访问总次数来重新获得效率。
在单个线程内实现最大一致性的一种简单方法是,一次针对一个场景对象处理批次中的所有光线,并从前到后依次处理场景对象。这种方法可以通过并行地对当前场景对象求交所有光线来朴素地并行化。然而,这种策略有两个主要缺点:第一,系统在每个场景对象处都有一个同步点;第二,等待场景对象加载会阻塞所有线程。
相反,在我们当前基于锥体的遍历系统中,我们在每个顶层层次节点处将遍历拆分为多个队列,每个线程处理不同的队列。由于多个线程可以在任何给定时间对不同场景对象的不同队列进行操作,因此对象加载不会阻塞所有并行线程。为了缓解所有光线同时命中同一对象的情况(这通常发生在尚未加载任何内容的第一批中),我们还对可追踪对象的初始化步骤(如曲面细分和位移)进行了多线程处理。
以这种方式“分散”遍历的问题在于,未命中某个对象的光线随后必须排队到遍历顺序中的下一个对象,但该对象可能已在另一个线程中被处理。每批次多次访问每个对象会影响我们的核外效率,因为它增加了需要重新加载可追踪对象的次数。此外,当重新加载可追踪对象时,我们会从头开始重新处理它(从磁盘读取网格描述、曲面细分、位移并构建 BVH),这使得即使具有最佳一致性也难以摊销成本。
我们对核外几何体的需求已通过增加可用内存、更广泛地使用实例化以及优化几何数据结构的存储占用而有所缓解。尽管如此,我们仍在尝试使用按对象的光线队列,推迟处理某个场景对象的光线以积累尽可能多的光线并摊销加载成本,同时我们也在研究预生成并缓存可追踪几何体的方法,以降低加载成本。
6.4 光线包与单光线遍历
对于光线包,由于我们的锥体-包围盒求交的高效性,我们的光线包遍历速度明显快于逐条遍历每条光线。此外,通过使用光线包,我们的排队开销得以降低,每个队列中所需的条目最多可减少 32 倍。然而,当小批次导致一致性下降时,光线包的锥体会变得非常宽,从而在顶层层次结构中失去剔除能力。这是我们一直容忍的偶发性低效问题,不过我们正在考虑禁用光线包,或者当检测到光线包远大于给定 BVH 节点时,动态地从光线包切换到单条光线。
6.5 管理几何复杂度
即使计算和内存容量稳步增长,制作上对更高几何复杂度的需求仍在持续有增无减。这种增长仅部分源于视觉复杂度的提升。艺术家使用的细节也超过了严格必要的程度,因为这样做通常能带来生产效率上的好处。紧张的制作周期几乎没有或根本没有时间来优化过度建模的资产或制作低细节版本。艺术家通常还发现,即使细节在相机中并不明显可见,使用精细的几何体来控制反射也更容易;这方面的例子包括飘散的布料纤维、角色皮肤上的毳毛、地面上的沙粒或冰粒,或表面上的尘埃颗粒。
渲染中庞大的几何体数量迫使我们做出妥协。我们更希望始终将曲面细分到亚像素尺寸(这是我们在 Reyes 中通常可以做到的),但为了节省内存,我们通常选择不这样做。尽管我们的细分率通常相当精细,但在缓慢移动的相机导致细分发生变化时,偶尔仍会粗糙到足以引起可见的跳变。必要时,可以通过从静态代表性相机位置固定细分来解决这些瑕疵。缺乏亚像素细分还要求使用 shading 法线来营造缺失的亚像素细节的假象,但 shading 法线远非理想,它要求为每个 shading 点计算位移导数(而不是在细分过程中进行简单的位移计算),从而增加了显著的成本,忽略了精细表面特征之间的阴影,并且当 shading 法线与几何表面差异很大时会引入瑕疵。
6.6 自动细节层次的尝试
细节层次(LOD)方法可以减少内存使用、渲染时间、噪点,或三者兼而有之。鉴于艺术家很少有时间管理手动 LOD 方案,自动方案颇具吸引力。然而,尽管我们在 Hyperion 中进行了几次自动细节层次的尝试,我们尚未找到可接受的方法。
我们在 Hyperion 中的首次 LOD 尝试受 Yoon et al. (2006) 的 R-LOD 工作启发,将平面拟合到近似叶几何体的内部 BVH 节点。当光线足迹大于 BVH 节点时,我们终止遍历。最初的光线穿透几何体问题导致使用包围板而非近似平面。瑕疵仍然是一个问题,但最大的问题是我们既未观察到速度提升,也未观察到内存节省。缩短遍历深度的潜在节省被额外的遍历复杂性所抵消。
我们的下一次尝试受到了 Laine 和 Karras(2010)的 Sparse Voxel Octree(SVO,稀疏体素八叉树)工作的启发。与我们之前的尝试类似,我们将包围平板拟合到八叉树节点的内容上,并拟合方向法线分布。通过这个系统,我们可以聚合任意几何体,对于远处的物体,内存减少 10–100 倍。不幸的是,我们发现聚合某些表面会产生令人反感的瑕疵,艺术家需要通过显式的 LOD 组选择性地启用 SVO。进一步阻碍采用的事实是,SVO 通常比非 LOD 几何体更慢,并且还显著增加了渲染过程的启动时间。虽然这些问题可能是可以克服的,但缺乏鲁棒性以及需要艺术家管理导致我们放弃了这种方法。
两种 LOD 方法中已部署到生产环境的一个组件是简化的 shading 模型。我们的“shading LOD”在三角形顶点预先计算并存储了 BSDF 模型的参数。和之前一样,当 shading 光线的足迹大于被 shading 的三角形时,将使用 shading LOD 而不是完整的 shading 器评估。虽然自动且大多成功,但它增加而非减少了内存使用,因为它仅对部分光线使用 shading LOD。更糟糕的是,它有时会减慢整体渲染迭代,因为启动时的 BSDF 参数评估发生在每个三角形顶点上,即使是三角形为亚像素的远处几何体也是如此。还存在一些可见的瑕疵,需要为某些表面禁用 shading LOD。虽然这本身并不是过重的负担,但它让人对渲染器输出的可靠性产生怀疑,这一点是有问题的。图像中的任何瑕疵都会立即引发问题:“你试过禁用 shading LOD 吗?”最终,收益无法证明成本,此功能被移除。
由于缺乏有效的自动 LOD 解决方案,我们遇到的最重要问题可能是由亚像素几何变化引起的噪声。一个场景可能在合理的时间内渲染完成且不超出内存预算,但亚像素几何细节仍可能引入过多的噪声。虽然内存和时间可以增加到一定程度,但此类噪声通常在任何合理的时间内都不会收敛。
6.7 逐面 texture 与单图像 texture
我们使用开源 Ptex 库进行所有 texture 的存储、缓存和过滤,包括逐面 texture 和“单图像”texture(其中单图像 texture 只是存储在仅包含一个面的 Ptex 文件中的传统 texture)。Ptex 最初开发主要是为了解决因高度精细 texture 化所需的大量 texture 文件而导致的 I/O 瓶颈(Burley 和 Lacewell 2008)。Ptex 提供的逐面 texture 还显著提高了工作流程效率,避免了手动分配 UV 或将表面分解为多个 texture 文件以管理 texture 分辨率的需要。出于这些原因,逐面 texture 构成了我们 texture 数据的主体,但单图像 texture 仍被使用,通常用于在没有创作或不需要独特 texture 时,用平铺投影快速覆盖物体。对两者都使用 Ptex 格式可以实现统一的缓存管理和过滤,尽管 Hyperion 的排序 shading 旨在为逐面 texture 访问提供最大的连贯性,单图像 texture 也能从中受益。
逐面 texture 和单图像 texture 在处理大过滤宽度时有所不同,例如,由间接漫反射光线的宽足迹导致的情况。单图像 texture 可以预先过滤到单个纹素,使得对于足够宽的过滤足迹,texture 访问成本可以忽略不计。相比之下,逐面 Ptex texture 仅针对每个面预先过滤到单个纹素。这限制了过度模糊,但增加了间接 shading 所需的数据访问。幸运的是,增加的数据访问通过一种特殊的逐面常量 texture 所缓解,该 texture 作为连续块存储在 Ptex 文件的前端,并覆盖整个映射网格。
值得指出的是,我们的许多 texture(甚至可能是大多数)是用于在材质层之间进行混合的遮罩。这些遮罩通常有大面积的恒定颜色,通常是黑色或白色。对于这些遮罩 texture,逐面 Ptex texture 特别有利,因为过滤器能够识别常量面,直接从上述逐面常量 texture 中读取,无需任何过滤核开销。
6.8 尝试替代采样技术的困难
Hyperion 被设计为能够从相机进行高效的单向 path tracing。因此,代码中存在许多假设和架构约束,有时会增加复杂性、降低效率,并使尝试替代采样技术变得困难。特别是,我们的积分代码目前高度分散,并内置于 shading 系统中。
例如,我们的光源采样代码并非在单一位置实现,而是部分实现在各个 shading 器中,部分实现在一些共享基础设施中。此外,直到最近,我们还没有区分使用 BSDF 采样创建的光线和使用光源采样创建的光线。因此,我们不得不拥有一个相对复杂的俄罗斯轮盘系统,适用于所有光线,并且我们无法实现诸如眼睛焦散之类的功能,这些功能需要为不同的光源分别创建光线,每条光线折射不同。
另一个例子是,我们的 photon mapping 系统分散在几个不同的区域,从迭代之间自定义的专用光子追踪通道,到在 shading 器内部实现的光子收集代码。理想情况下,我们希望有一个专用的 integrator 来处理 photon mapping 计算。
7 结论
我们介绍了迪士尼 Hyperion 渲染器的架构和开发,以及在三部动画长片过程中遇到的诸多挑战。我们还分析并讨论了 Hyperion 架构中的各种优势和不足。Hyperion 为我们的电影制作流程带来了显著改进,并持续发展以满足工作室渲染新现象、提高艺术家效率以及最终创作出最高质量电影的需求。
致谢
除了本文作者之外,许多人贡献了迪士尼 Hyperion 渲染器的开发。Hyperion 的原始架构由 Brent Burley 提出,并由 Christian Eisenacher、Gregory Nichols 和 Andrew Selle 开发。Benedikt Bitterli、Simon Kallweit、Gabor Liktor、Ulrich Muller、Jan Novák、Ben Spencer 和 Serge Sretschinsky 也进行了重要的 Hyperion 开发工作。
我们感谢与 Disney Research、Pixar Research 以及 RenderMan 开发团队的许多深入讨论,这些讨论影响了 Hyperion 的开发,尤其要感谢 Per Christensen、Julian Fong、Christophe Hery、Wojciech Jarosz、Marios Papas、Thomas Müller、Fabrice Rouselle、Rasmus Tamstorf、Ryusuke Villemin 和 Magnus Wrenninge。
我们感谢 Sean Jenkins、Darren Robinson、Rajesh Sharma 和 Chuck Tappan 的领导与管理支持;感谢 Andrew Fisher 和 Tami Valdes 的项目管理;以及 Doug Lesan 和 Lisa Young 的质量工程。
最重要的是,我们要感谢众多艺术家、技术指导与制作主管,他们激励了 Hyperion、参与了其开发并为其成功做出了贡献,尤其要感谢 Big Hero 6 的领导层敢于迈出信任的一步。我们还要感谢管线软件开发团队、技术部门以及工作室领导层对我们工作的支持。