沃尔特·迪斯尼动画工作室(WDAS)最近通过发布
Moana卡通的
完整岛屿场景 ,向渲染研究界做出了无价之宝。 一帧的几何和纹理占用70 GB以上的磁盘空间。 这是当今渲染系统必须处理的复杂程度的一个极好的例子。 电影制片厂之外从事渲染工作的研究人员和开发人员以前从未能够使用这种逼真的场景。
使用现代pbrt渲染场景的结果如下所示:
由pbrt-v3渲染的Moana岛,分辨率为2048x858,每个像素256个样本。 在最新版本的pbrt-v3的频率为2 GHz的Google Compute Engine的12核/ 24线程实例上,总渲染时间为1小时44分45秒。在迪士尼方面,这是一项艰巨的工作,她不得不从场景本身的内部格式中提取场景并将其转换为通常的格式。 特别感谢她花了很多时间来打包和准备这些数据以供广泛使用。 我相信他们的工作将来会得到很好的回报,因为研究人员使用此场景来研究有效渲染这种复杂程度的场景的问题。
这个场景已经教给了我很多知识,使我能够改进pbrt渲染器,但是在开始之前,我会先讲一个简短的故事以了解上下文。
没有的哈希
许多年前,在Pixar渲染团队实习期间,我吸取了一个奇怪的教训:“有趣”的东西几乎总是在输入数据传递到程序系统时出现,这与以前的一切大不相同。 即使在编写良好且成熟的软件系统中,新型输入几乎总是导致发现现有实现中的未知缺陷。
我首先在制作《
玩具总动员2》时学习了这一课。 一天,有人注意到解析RIB场景描述文件花费了惊人的时间。 渲染团队的其他人(我猜是Craig Kolb)启动了探查器并开始弄清楚它。
事实证明,大部分解析时间都被用于
字符串实习的哈希表中的搜索所占用。 哈希表很小,可能有256个元素,并且当几个值被哈希到一个单元格中时,它组织了一条链。 在第一次实现哈希表之后,经过了很多时间,现在场景中有成千上万个对象,因此,这样的小表很快就被填充而变得无效。
最好只是增加表格的大小-所有这些都是在工作流程的高度进行的,因此没有时间采取某种优雅的解决方案,例如,在填写表格时扩大表格的大小。 我们只做一行更改,重新构建应用程序,在提交之前执行快速测试,并且...没有速度改进。 搜索哈希表需要花费相同的时间。 太棒了!
经过进一步研究,我们发现所使用的哈希表函数类似于以下内容:
int hash(const char *str) { return str[0]; }
(请原谅我,皮克斯,如果我透露了您的绝密RenderMan源代码。)
“哈希”功能是在1980年代实现的。 那时,程序员可能认为检查字符串中所有字符对哈希值的影响的计算成本太高了,不值得。 (我认为,如果场景中的哈希表中只有几个对象和256个元素,那就足够了。)
另一个过时的实现方式是:从Pixar开始制作电影的那一刻起,场景中物体的名称就增长了很多,例如“ BuzzLightyear / LeftArm / Hand / IndexFinger / Knuckle2”。 但是,在管道的某些初始阶段,使用了固定长度的缓冲区来存储对象的名称,并缩短了所有长名称,只保留了结尾,并且幸运的是,在开头添加了省略号,从而清楚地表明该名称的一部分丢失了:“ ...年/ LeftArm / Hand / IndexFinger / Knuckle2“。
随后,渲染器看到的所有对象名称都具有这种形式,哈希函数将它们全部存储在一块内存中,称为“。”,而哈希表实际上是一个很大的链表。 美好的过去。 至少在弄清楚了之后,我们迅速修复了该错误。
有趣的创新
去年,当来自WDAS的Heather Pritchet和Rasmus Tamstorf与我联系并询问我是否对检查
pbrt 1中 Moana的场景渲染的质量是否感兴趣时,这个课程被我铭记。 自然,我同意了。 我很乐意提供帮助,我想知道一切将如何发展。
我内心的天真乐观主义者希望不会有太大的惊喜-最终,大约15年前发布了pbrt的第一版,很多人使用和研究了很多年。 您可以确定不会像RenderMan的旧哈希函数那样产生干扰,对吗?
当然,答案是否定的。 (这就是为什么我写这篇文章和其他几篇文章的原因。)尽管我对pbrt并非“开箱即用”并不完美感到失望,但是我认为我对
Moana场景的体验是对发布该场景的价值的首次确认。 ; 由于我想出了如何处理这个事实,pbrt已经成为一个更好的系统。
首批效果图
进入场景后,我立即下载了该图像(与家庭Internet连接花费了几个小时),并从tar中解压缩了该图像,并接收了29 GB的pbrt文件和38 GB的
ptex 2纹理贴图。 我巧妙地尝试在我的家庭系统(具有16 GB的RAM和4核CPU)上渲染场景。 一段时间后返回计算机后,我看到它已冻结,所有RAM都已满,而pbrt仍在尝试完成场景描述的解析。 操作系统试图使用虚拟内存来处理该任务,但似乎毫无希望。 打败了这个过程之后,我不得不等待大约一分钟,系统才能开始响应我的行为。
下一次尝试是Google Compute Engine实例,它允许您使用更多的RAM(120 GB)和更多的CPU(16个CPU上32个线程)。 好消息是pbrt能够成功渲染场景(由于Heather和Rasmus的工作将其转换为pbrt格式)。 看到pbrt可以为高质量的电影内容生成相对较好的像素非常令人兴奋,但事实证明速度并不那么惊人:34分58秒仅用于解析场景描述,并且在渲染过程中系统花费了高达70 GB的RAM。
是的,磁盘上有29 GB的pbrt格式场景描述文件需要稀疏存储,因此我并不期望第一阶段花费几秒钟的时间。 但是要花半小时甚至在光线开始追迹之前? 这大大增加了场景的工作。
另一方面,这种速度告诉我们,代码中可能发生了非常难闻的气味。 不仅是“矩阵反转可以快10%”; 确切地说,是“哦,我们正在遍历10万个元素的链表”。 我很乐观,并希望弄清楚这一点,可以大大加快这一过程。
统计资料无济于事
我首先寻找线索的地方是渲染后的pbrt dump统计信息。 配置了pbrt执行的主要阶段,以便您可以通过在渲染过程中固定操作(具有周期性中断)来收集大概的性能数据。 不幸的是,统计数据对我们没有太大帮助:据报道,从渲染开始前的将近35分钟,构建BVH花了4分22秒,但其余时间未提供任何详细信息。
建立BVH是场景解析期间执行的唯一重要的计算任务; 其他所有内容本质上都是几何和材料描述的反序列化。 知道花了多少时间创建BVH,可以了解系统的有效性(无效):剩余时间(即大约30分钟)解析了29 GB的数据,即速度为16.5 MB / s。 经过优化的JSON解析器,基本上执行相同的任务,运行速度为50-200 MB / s。 显然,仍有改进的空间。
为了更好地了解浪费的时间,我使用从未使用过的Linux性能工具启动了pbrt。 但是,看来,他应付了任务。 我指示他搜索DWARF字符以获取函数名称(
--call-graph dwarf
),并且为了不获取100 GB的跟踪文件,我不得不将采样率从每秒4000个样本降低到100个样本(
-F 100
)。 但是有了这些参数,一切就一切顺利了,我感到非常惊讶的是,性能
perf report
工具的界面具有很好的诅咒效果。
从pbrt开始后,他可以告诉我的是:
当我谈论“具有良好诅咒的界面”时,我并不是在开玩笑。我们看到一半以上的时间都花在解析力学上:
yyparse()
是
yyparse()
生成的
yyparse()
,而
yylex()
是
flex生成的词法分析器(lexer)。
yylex()
超过一半的时间都花在
strtod()
,它将字符串转换为双
strtod()
值。 我们将对
yyparse()
和
yylex()
yyparse()
攻击
yyparse()
本系列的第三篇文章之前,但是现在我们已经可以理解,减少抛出到渲染器中的数据量可能是一个好主意。
从文本到PLY
花费较少时间解析文本数据的一种方法是将数据转换为更有效地解析的格式。 这些场景描述文件中的29 GB大部分是三角形网格,而pbrt已经
对PLY格式提供了
本机支持,
PLY格式是多边形网格的有效二进制表示形式。 同样在pbrt中有一个命令行标志
--toply
,它解析场景描述文件pbrt,将找到的所有三角形网格转换为PLY文件,并创建一个引用这些PLY文件的新pbrt文件。
问题在于,在迪士尼场景中积极使用了
ptex纹理,这反过来又要求将
faceIndex
值与每个三角形相关联,从而确定要从其获取原始子网格的哪个面。 要传输这些值,只需
在PLY文件中添加对新字段的支持就足够了。 进一步的研究表明,在将每个网格(即使只有十二个三角形)转换为PLY文件的情况下,该文件夹中也会创建成千上万个小的PLY文件,这会产生其自身的性能问题。 我们通过在实现中增加了
使小网格保持不变的
能力来解决了这个问题。
我编写了一个
小的命令行脚本来转换文件夹中的所有
*_geometry.pbrt
文件,以将PLY用于大型网格。 请注意,它具有关于路径的硬编码假设,需要更改这些路径才能使脚本在其他地方工作。
第一次提速
将所有大网格物体转换为PLY之后,磁盘上的场景描述大小从29 GB减少到22 GB:16.9 GB的pbrt场景文件和5.1 GB的PLY二进制文件。 转换后,系统第一阶段的总时间减少到27分35秒,节省的时间为7分23秒,也就是说,我们加快了1.3倍
3 。 处理PLY文件比处理pbrt文本文件效率更高:解析PLY文件只花了40秒的启动时间,而且我们看到PLY文件的处理速度约为130 MB / s,比pbrt文本格式快大约8倍。 。
这是一次轻松的胜利,但是我们还有很多事情要做。
下次,我们将弄清所有内存的实际使用位置,在此修复一些错误,并提高处理速度。
注意事项
- 现在,您应该对我增加了ptex支持并在去年将Disney BSDF转换为pbrt的动机有了更好的了解。
- 在此以及以后的所有帖子中,所有时间都是针对WIP版本(进行中的工作)的,我在正式发布之前就曾使用过该版本。 最终版本似乎要大一些。 我们将坚持使用我在原始场景下录制的结果,尽管它们与最终版本的结果并不完全相同。 我怀疑他们的教训是一样的。
- 请注意,速度的提高本质上就是您期望的,而解析数据量减少了约50%。 我们根据分析器所花费的时间证实了我们的想法。