提高光线跟踪器的性能

时间:2009-04-22 16:05:08

标签: performance graphics d raytracing

我在D(http://dsource.org/projects/stacy)中编写了一个相对简单的光线跟踪器/路径跟踪器,但即使完全优化,它仍然需要每条光线数千个处理器周期。我还能做些什么来加快速度吗?更一般地说,您是否知道光线跟踪的良好优化/更快的方法?

编辑:这就是我现在正在做的事情。

  • 代码已经高度并行运行
  • 临时数据以高效缓存方式构建,并与16b
  • 对齐
  • 屏幕划分为32x32-tiles
  • 目标数组的排列方式使得图块中的所有后续像素在内存中是连续的
  • 执行基本场景图优化
    • 对象的常见组合(如框中的平面平面CSG)被预先优化的对象替换
  • 能够利用GDC自动矢量化支持的Vector结构
  • 通过懒惰评估找到对射线的后续命中;这可以防止对CSG进行不必要的计算
  • 三角形既不支持也不优先。仅限普通基元,以及CSG操作和基本材料属性
  • 支持边界

9 个答案:

答案 0 :(得分:10)

光线跟踪器速度的典型一阶改进是某种空间分区方案。仅基于您的项目大纲页面,您似乎还没有这样做。

最常见的方法可能是八叉树,但最好的方法可能是方法的组合(例如空间分区树和邮箱之类的东西)。边界框/球体测试是一种快速廉价且令人讨厌的方法,但你应该注意两件事:1)它们在许多情况下没有太大帮助; 2)如果你的对象已经是简单的原始体,你将不会获得太多(甚至可能输了)。您可以更容易地(比八叉树)实现用于空间分区的常规网格,但它仅适用于有些均匀分布的场景(就表面位置而言)

很大程度上取决于您所代表的对象的复杂程度,您的内部设计(即您是否允许局部变换,对象的引用副本,隐式曲面等),以及您尝试的准确程度。如果您正在编写具有隐式曲面的全局照明算法,那么权衡可能与您为网格对象或其他任何东西编写基本光线跟踪器时有所不同。我没有详细看过你的设计,所以我不确定你已经考虑过的上述内容是什么,如果有的话。

与任何性能优化过程一样,您将首先必须先测量以找到您实际花费时间的位置,然后改进(通过优先选择算法,然后根据需要编写代码)

答案 1 :(得分:7)

我用光线跟踪器学到的一件事是,很多旧规则不再适用了。例如,许多光线跟踪算法进行了大量测试以获得计算上昂贵的计算的“早期”。在某些情况下,我发现消除额外测试并总是运行计算完成要好得多。算术在现代机器上很快,但错过的分支预测是昂贵的。通过用最小的条件分支重写它,我在光线 - 多边形交叉点测试中获得了30%的加速。

有时最好的方法是违反直觉的。例如,我发现当我将它们分解成大量较小的对象时,许多具有几个大对象的场景运行得更快。根据场景几何图形,这可以允许您的空间细分算法抛出大量的交叉测试。让我们面对现实,相交测试只能这么快。你必须消除它们以获得显着的加速。

分层边界体积有很大帮助,但我终于找到了kd-tree,并且速度有了很大的提升。当然,构建树的成本可能使其无法用于实时动画。

注意同步瓶颈。

您必须确定要将注意力集中在正确的位置。

答案 2 :(得分:6)

我还能做些什么来加快速度吗?

D,取决于实现和编译器,提出了相当好的性能。由于您尚未解释您已使用的光线跟踪方法和优化,因此我无法为您提供太多帮助。

接下来,下一步是对程序进行时序分析,并重新编码最常用的代码或最慢的代码,而不是影响组装中的性能。

更一般地说,请查看以下问题中的资源:

我非常喜欢使用显卡(大规模并行计算机)来完成某些工作。

此网站上还有许多其他与光线追踪相关的资源,其中一些资源列在此问题的侧边栏中,其中大部分都可以在raytracing tag中找到。

答案 3 :(得分:3)

我根本不知道D,所以我无法查看代码并找到具体的优化,但我可以说一般。

这实际上取决于您的要求。最简单的优化之一就是减少任何特定光线可以遵循的反射/折射次数,但是你会开始失去“完美结果”。

光线跟踪也是一个"embarrassingly parallel"问题,因此如果你有资源(例如多核处理器),你可以考虑并行计算多个像素。

除此之外,您可能只需要分析并弄清楚究竟需要花费多长时间,然后尝试对其进行优化。是交叉口检测吗?然后开始优化代码,依此类推。

答案 4 :(得分:3)

一些建议。

  • 使用边界对象快速失败。
  • 第一步投影场景(如普通图形卡所示)并仅使用光线追踪进行光线计算。
  • 并行化代码。

答案 5 :(得分:3)

每隔一个像素光线追踪。通过插值获取颜色。如果颜色变化很大(您位于对象的边缘),则光线跟踪其间的像素。这是作弊,但在简单的场景中,你可以在牺牲一些图像质量的同时将性能提高一倍。

在GPU上渲染场景,然后将其加载回来。这将为您提供GPU速度下的第一个光线/场景命中。如果场景中没有很多反射表面,这会将大部分工作减少为普通旧渲染。遗憾的是,在GPU上渲染CSG并非完全直截了当。

阅读PovRay的源代码以获取灵感。 :)

答案 6 :(得分:2)

你首先要确保你使用非常快的算法(实现它们可能是一个真正的痛苦,但你想做什么,你想要走多远,它应该有多快,这是一种tradeof)。

我的一些提示 - 不要使用邮箱技术,在论文中有时会讨论它们由于计数开销而无法与实际体系结构很好地扩展 - 不要使用BSP /八叉树,它们相对较慢。 - 不要使用GPU进行光线跟踪,对于高级效果(如反射和阴影,折射和光子映射等)来说太慢了(我只将它用于着色,但这是我的啤酒)

对于一个完整的静态场景kd-Trees是无与伦比的,对于动态场景,有一些聪明的算法可以在四核上很好地扩展(我不确定上面的性能)。

当然,为了获得真正良好的性能,你需要使用非常多的SSE代码(当然没有太多的跳跃)但是因为没有“那么好”的性能(我在这里谈论的可能是10-15%)编译器 - 内在函数很有助于实现你的SSE。

关于我正在讨论的一些算法的一些不错的论文:

“快速光线/轴对齐边界框 - 使用光线斜坡进行重叠测试” (非常快速非常好的paralelisizable(SSE)AABB-Ray命中测试)(注意,论文中的代码不是所有代码,只是谷歌的文章标题,你会发现它)

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模型)等等)有如此多的主题,有很多很好的论文,它是一个真正令人惊讶且有趣的“试验”领域,但你需要有很多空闲时间,因为它太复杂而且很有趣。

答案 7 :(得分:0)

我的第一个问题是 - 您是否正在尝试优化单个静态屏幕的跟踪, 或者这是为了优化多个屏幕的跟踪以计算动画?

优化单次拍摄是一回事,如果要计算动画中的连续帧,需要考虑/优化许多新事物。

答案 8 :(得分:0)

你可以

  • 使用SAH优化的边界卷层次结构......
  • ...最终使用数据包遍历,
  • 介绍重要性抽样,
  • 访问按Morton代码排序的切片,以获得更好的缓存一致性,

更多 - 但这些是我能立即想到的建议。换句话说:

您可以基于统计数据构建优化的层次结构,以便在交叉几何体时快速识别候选节点。在您的情况下,您必须将自动层次结构与建模层次结构相结合,即约束构建或最终克隆建模信息。

“数据包遍历”意味着您使用SIMD指令计算4个并行标量,每个标量用于遍历层次结构(通常是热点),以便从硬件中挤出最大的性能。

您可以执行一些每光线统计数据,以便根据对结果像素颜色的贡献来控制采样率(拍摄的次级光线数量)。

使用磁贴上的区域曲线可以减少像素之间的平均空间距离,从而降低性能从缓存命中中受益的概率。