提高光线追踪器的性能
Posted
技术标签:
【中文标题】提高光线追踪器的性能【英文标题】:Improving raytracer performance 【发布时间】:2010-10-21 03:36:33 【问题描述】:我正在用 D (http://dsource.org/projects/stacy) 编写一个相对简单的光线追踪器/路径追踪器,但即使经过全面优化,每条光线仍需要数千个处理器周期。我还能做些什么来加快速度吗?更一般地说,您知道光线追踪的良好优化/更快的方法吗?
编辑:这是我已经在做的。
代码已经高度并行运行 临时数据以缓存效率高的方式结构化,并与 16b 对齐 屏幕分为 32x32 块 目标数组的排列方式使得一个图块中的所有后续像素在内存中都是连续的 已执行基本场景图优化 对象的常见组合(如方框中的平面-平面 CSG)已替换为预优化的对象 能够利用 GDC 的自动矢量化支持的矢量结构 射线上的后续命中是通过惰性求值找到的;这可以防止对 CSG 进行不必要的计算 三角形既不支持也不优先。仅限普通图元,以及 CSG 操作和基本材料属性 支持边界【问题讨论】:
FeepingCreature,如果时序分析告诉您,这是您的光线/平面光线/球体交叉点是使用时间的地方,那么答案是做更少的测试。除非我当时错过了什么,否则我对空间分区的评论似乎是正确的方向。 【参考方案1】:我从光线追踪器中学到的一件事是,许多旧规则不再适用。例如,许多光线追踪算法会进行大量测试以“尽早”完成计算量大的计算。在某些情况下,我发现消除额外的测试并始终运行计算以完成要好得多。算术在现代机器上很快,但错过的分支预测代价高昂。通过用最少的条件分支重写它,我的光线-多边形相交测试的速度提高了 30%。
有时最好的方法是违反直觉的。例如,当我将它们分解为大量较小的对象时,我发现许多包含几个大对象的场景运行得更快。根据场景几何,这可以让您的空间细分算法抛出大量的交叉测试。让我们面对现实吧,相交测试只能这么快进行。您必须消除它们才能获得显着的加速。
分层边界体积有很大帮助,但我最终摸索了 kd-tree,并获得了巨大的速度提升。当然,构建树的成本可能会让实时动画望而却步。
注意同步瓶颈。
您必须进行简介以确保将注意力集中在正确的位置。
【讨论】:
反直觉是当今许多事情的方式。十年前我对优化的了解完全不在了。分支预测是非常重要的理解。【参考方案2】:你可以
使用 SAH 优化的包围体层次结构... ...最终使用数据包遍历, 引入重要性采样, 访问按 Morton 代码排序的切片以获得更好的缓存一致性,并且更多 - 但这些是我能立即想到的建议。更多的话:
您可以根据统计信息构建优化的层次结构,以便在与几何图形相交时快速识别候选节点。在您的情况下,您必须将自动层次结构与建模层次结构结合起来,即约束构建或让它最终克隆建模信息。
“数据包遍历”是指您使用 SIMD 指令来计算 4 个并行标量,每个标量都有自己的射线,用于遍历层次结构(通常是热点),以充分利用硬件的性能。
您可以执行一些每条光线的统计数据,以便根据对生成的像素颜色的贡献来控制采样率(二次光线拍摄的数量)。
在图块上使用面积曲线可以减少像素之间的平均空间距离,从而降低缓存命中率带来的性能优势。
【讨论】:
【参考方案3】:光线追踪每隔一个像素。通过插值获得中间的颜色。如果颜色变化很大(您位于对象的边缘),请对中间的像素进行光线追踪。这是作弊,但在简单的场景中,它几乎可以在牺牲一些图像质量的同时将性能提高一倍。
在 GPU 上渲染场景,然后将其加载回来。这将为您提供以 GPU 速度命中的第一条光线/场景。如果场景中没有很多反射表面,这会将您的大部分工作减少为普通的旧渲染。不幸的是,在 GPU 上渲染 CSG 并不完全简单。
阅读 PovRay 的源代码以获得灵感。 :)
【讨论】:
【参考方案4】:你必须首先确保你使用非常快的算法(实现它们可能真的很痛苦,但是你想做什么,你想走多远,应该多快,这是一种权衡)。
我的更多提示 - 不要使用邮箱技术,在论文中有时会讨论由于计数开销,它们无法与实际架构很好地扩展 - 不要使用 BSP/Octtrees,它们相对较慢。 - 不要使用 GPU 进行光线追踪,它对于反射和阴影、折射和光子映射等高级效果来说太慢了(我只将它用于着色,但这是我的啤酒)
对于一个完整的静态场景,kd-Trees 是无与伦比的,对于动态场景,有一些聪明的算法可以很好地在四核上扩展(我不确定上面的性能)。
当然,为了获得真正好的性能,您需要使用非常多的 SSE 代码(当然不会有太多的跳转),但对于不是“那么好”的性能(我在这里谈论的可能是 10-15%)编译器-内在函数足以实现您的 SSE 东西。
还有一些关于我正在谈论的算法的不错的论文:
“快速射线/轴对齐边界框 - 使用射线斜率的重叠测试” (very fast very good paralelisizable (SSE) AABB-Ray hit test)(注意,论文中的代码并不是全部代码,只要google一下论文的标题就可以找到了)
http://graphics.tu-bs.de/publications/Eisemann07RS.pdf
“使用动态边界体积层次结构的光线追踪可变形场景”
http://www.sci.utah.edu/~wald/Publications/2007///BVH/download//togbvh.pdf
如果您知道上述算法的工作原理,那么这是一个更强大的算法:
“在动态场景中使用预先计算的三角形集群进行加速光线追踪”
http://garanzha.com/Documents/UPTC-ART-DS-8-600dpi.pdf
我还使用 pluecker-test 来快速确定(不是那么准确,但好吧,你不能拥有所有)如果我击中一个多边形,在 SSE 及更高版本上工作得非常好。
所以我的结论是,那里有很多很棒的论文,涉及很多与光线追踪相关的主题(如何构建快速、高效的树以及如何着色(BRDF 模型)等等),它是一个非常神奇和有趣的“实验”领域,但你也需要有很多空闲时间,因为它非常复杂但很有趣。
【讨论】:
【参考方案5】:我的第一个问题是 - 您是否尝试优化单个静止屏幕的跟踪, 或者这是关于优化多个屏幕的跟踪以计算动画?
针对单个镜头进行优化是一回事,如果您想计算动画中的连续帧,则需要考虑/优化很多新事物。
【讨论】:
【参考方案6】:我还能做些什么来加快速度吗?
D,取决于实现和编译器,提出了相当好的性能。由于您还没有解释您已经使用了哪些光线追踪方法和优化,所以我无法为您提供太多帮助。
然后,下一步是对程序运行时序分析,并重新编码最常用的代码或最慢的代码,而不是在汇编中对性能影响最大。
更一般地,请查看以下问题中的资源:
Literature and Tutorials for Writing a Ray Tracer Anyone know of a really good book about Ray Tracing? Computer Graphics: Raytracing and Programming 3D Renders raytracing with CUDA我真的很喜欢使用显卡(大规模并行计算机)来完成一些工作的想法。
本站还有很多其他的光线追踪相关资源,部分在本题侧边栏列出,大部分可以在raytracing tag找到。
【讨论】:
我试图远离装配 :) 对光线命中进行延迟评估,并执行基本的场景图优化(将平移合并到旋转矩阵中,诸如此类)。时序分析表明,射线/球体和射线/平面代码占用了大部分时间,但老实说,我认为在完全优化方面我不能比 GDC 做得更好。【参考方案7】:光线追踪器速度的典型一阶改进是某种空间分区方案。仅根据您的项目大纲页面,您似乎还没有这样做。
可能最常用的方法是八叉树,但最好的方法可能是多种方法的组合(例如空间分区树和邮箱等)。边界框/球体测试是一种快速廉价且令人讨厌的方法,但您应该注意两点:1)它们在许多情况下没有多大帮助;2)如果您的对象已经是简单的基元,您将不会获得太多收益(甚至可能会输)。您可以更轻松地(比八叉树)实现用于空间分区的规则网格,但它仅适用于稍微均匀分布的场景(就表面位置而言)
很大程度上取决于您所代表的对象的复杂性、您的内部设计(即您是否允许本地变换、对象的引用副本、隐式曲面等),以及您想要达到的准确度。如果您正在编写具有隐式表面的全局照明算法,则权衡可能与您正在为网格对象或其他任何东西编写基本光线追踪器时有所不同。我没有详细查看您的设计,所以我不确定您已经考虑过上述哪些内容(如果有的话)。
与任何性能优化过程一样,您必须首先进行衡量以找到实际花费时间的地方,然后改进事物(根据偏好进行算法,然后根据需要编写代码)
【讨论】:
已被证明工作得最好的数据结构是 kd-trees(用于可以轻松拆分的简单几何图元)和边界体积层次结构(用于无法轻松拆分的更复杂的图元) .通常这些树是平衡的,考虑两个嵌套框的表面积的商来估计随机射线与内框相交的概率(这种考虑通常称为表面积启发式)。参见例如Havran 的研究 (dcgi.felk.cvut.cz/home/havran/publications.html) 他的大部分论文都致力于索引 rt 场景。【参考方案8】:一些建议。
使用边界对象快速失败。 首先投影场景(与普通显卡一样),并仅将光线跟踪用于光照计算。 并行化代码。【讨论】:
【参考方案9】:我根本不懂D,所以看代码也找不到具体的优化,但我能说得通。
这真的取决于您的要求。最简单的优化之一就是减少任何特定光线可以跟随的反射/折射的数量,但随后您开始失去“完美结果”。
光线追踪也是"embarrassingly parallel" 的问题,所以如果您有资源(例如多核处理器),您可以考虑并行计算多个像素。
除此之外,您可能只需要分析并弄清楚究竟是什么花费了这么长时间,然后尝试对其进行优化。是路口检测吗?然后着手为此优化代码,等等。
【讨论】:
它已经高度平行了 :) 问题是,初步分析似乎表明射线/球体和射线/平面碰撞测试花费的时间最长,而且,我不知道该怎么办他们。我已经在尽我所能预先计算。以上是关于提高光线追踪器的性能的主要内容,如果未能解决你的问题,请参考以下文章