代码之家  ›  专栏  ›  技术社区  ›  FeepingCreature

提高光线跟踪器性能

  •  18
  • FeepingCreature  · 技术社区  · 15 年前

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

    编辑:这就是我已经在做的。

    • 代码已经在高度并行运行
    • 临时数据以高效缓存的方式构造,并与16b对齐
    • 屏幕分为32x32块
    • 目的地阵列的排列方式使得磁贴中的所有后续像素在存储器中是连续的
    • 执行基本的场景图优化
      • 对象的常见组合(框中的平面CSG)替换为预先优化的对象
    • 利用GDC自动矢量化支持的向量结构
    • 通过延迟计算可以找到射线的后续命中;这可以防止对CSG进行不必要的计算
    • 三角形既不支持也不优先。仅限于纯原语,以及CSG操作和基本材质属性
    • 支持边界
    9 回复  |  直到 15 年前
        1
  •  10
  •   simon    15 年前

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

    可能最常用的方法是八叉树,但最好的方法很可能是方法的组合(例如,空间划分树和像邮件装箱之类的东西)。Bounding box/sphere测试是一种快速、廉价和令人讨厌的方法,但您应该注意两件事:1)它们在许多情况下没有多大帮助;2)如果您的对象已经是简单的原语,则不会获得太多(甚至可能会失去)。您可以更容易地(比八叉树)实现用于空间分区的规则网格,但它只适用于稍微均匀分布的场景(就表面位置而言)

    很大程度上取决于你所代表的对象的复杂性,你的内部设计(即,你是否允许局部变换、对象的参考拷贝、隐式表面等等),以及你想做的精确程度。如果编写的是具有隐式曲面的全局照明算法,则折衷可能与为网格对象或其他对象编写基本光线跟踪器有所不同。我还没有详细看过你的设计,所以我不确定你是否已经考虑过上面的内容。

    与任何性能优化过程一样,您必须首先进行度量,以找到实际花费时间的地方,然后改进一些东西(从算法上优先考虑,然后根据需要进行代码编译)

        2
  •  7
  •   Adrian McCarthy    10 年前

    我从光线跟踪器中学到的一件事是,很多旧规则不再适用。例如,许多光线跟踪算法都会进行大量测试,以“提前”完成计算成本高昂的计算。在某些情况下,我发现消除额外的测试并始终运行计算到完成要好得多。在现代机器上,运算速度很快,但漏掉的分支预测代价很高。通过用最小条件分支重写光线多边形交集测试,我得到了大约30%的加速。

    有时候最好的方法是反直觉的。例如,我发现当我将许多场景分解成大量较小的对象时,其中包含一些大型对象的场景运行得更快。根据场景几何体的不同,这可以让空间细分算法抛出许多交集测试。让我们面对现实吧,交叉口测试只能这么快。你必须消除它们才能显著加快速度。

    层次化的边界卷帮助很大,但我最终摸索了kd树,并获得了巨大的速度增长。当然,构建树的成本可能会使其对实时动画望而却步。

    注意同步瓶颈。

    你必须做个侧写,确保把注意力集中在正确的地方。

        3
  •  6
  •   Community gkalpak    7 年前

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

    D、 根据实现和编译器,提出了合理的良好性能。由于您还没有解释您已经使用了哪些光线跟踪方法和优化,因此我无法在那里为您提供太多帮助。

    然后,下一步是对程序运行计时分析,并重新编码最常用的代码或比在程序集中影响性能最慢的代码。

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

    我真的很喜欢用一个图形卡(一个大型并行计算机)来做一些工作。

    这个站点上还有许多其他与光线跟踪相关的资源,其中一些资源列在这个问题的侧边栏中,其中大部分可以在 raytracing tag .

        4
  •  3
  •   Chad Birch    15 年前

    我根本不知道D,所以我无法查看代码并找到特定的优化,但我可以泛泛地说。

    这真的取决于你的要求。最简单的优化之一就是减少任何特定光线可以跟随的反射/折射的数量,但随后你就开始失去“完美结果”。

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

    除此之外,您可能只需要分析并找出究竟什么花费了这么长时间,然后尝试优化。是交叉口检测吗?然后优化代码,依此类推。

        5
  •  3
  •   Daniel Brückner Pradip    15 年前

    一些建议。

    • 使用边界对象快速失败。
    • 在第一步投影场景(就像普通的图形卡一样),并仅将光线跟踪用于灯光计算。
    • 将代码并行化。
        6
  •  3
  •   Roman Zenka    14 年前

    每隔一个像素进行光线跟踪。通过插值得到中间的颜色。如果颜色变化很大(你在一个物体的边缘上),光线跟踪中间的像素。这是欺骗,但在简单的场景中,它几乎可以加倍的性能,而你牺牲一些图像质量。

    在GPU上渲染场景,然后将其加载回。这将给你以GPU速度拍摄的第一个光线/场景。如果场景中没有许多反射曲面,则这会将大部分工作减少到普通的旧渲染。不幸的是,在GPU上呈现CSG并不是完全直接的。

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

        7
  •  2
  •   Quonux    14 年前

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

    我再给你点提示 -不要使用邮件装箱技术,有时在论文中讨论,由于计数开销,它们与实际体系结构不太好。 -不要使用BSP/octrees,它们比较慢。 - 不要 使用GPU进行光线跟踪,对于反射和阴影、折射和光子映射等高级效果来说,它太慢了(我只用于着色,但这是我的啤酒)

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

    当然,要获得真正好的性能,您需要使用非常多的SSE代码(当然不需要太多跳转),但要获得“不那么好”的性能(我在这里说的可能是10-15%),编译器内部函数是实现SSE的唯一方法。

    还有一些关于我所说的一些算法的像样的论文:

    快速光线/轴对齐包围盒-使用Ray Slopes的重叠测试 (非常快非常好的并行(SSE)AABB射线击中测试)(注意,论文中的代码并不全是代码,只是谷歌为论文标题,你会找到它)

    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测试来快速确定(不是thaat精确,但你不可能拥有全部)如果我击中一个多边形,在SSE和更高的情况下效果非常好。

    所以我的结论是,有那么多关于光线追踪(如何建立快速有效的树和如何遮荫(BRDF模型)等)的主题的伟大论文,这是一个真正令人惊奇和有趣的“实验”领域,但你也需要有很多业余时间,因为它是如此的复杂,但有趣。

        8
  •  0
  •   Led    15 年前

    我的第一个问题是-你想优化一个静止屏幕的跟踪吗, 或者这是为了优化多个屏幕的跟踪以计算动画?

    优化一个镜头是一回事,如果你想计算动画中的连续帧,有很多新的事情要考虑/优化。

        9
  •  0
  •   Dude    12 年前

    你可以

    • 使用SAH优化的边界卷层次结构。。。
    • …最终使用包遍历,
    • 引入重要性抽样,
    • 访问按Morton代码排序的tiles以获得更好的缓存一致性,以及

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

    可以基于统计信息构建优化的层次结构,以便在与几何体相交时快速识别候选节点。在您的案例中,您必须将自动层次结构与建模层次结构相结合,即要么约束构建,要么让它最终克隆建模信息。

    “数据包遍历”是指使用SIMD指令计算4个并行标量,每个标量都是一条自己的射线,用于遍历层次结构(通常是热点),以便从硬件中获得最高性能。

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

    使用平铺上的面积曲线可以减少像素之间的平均空间距离,从而降低缓存命中率对性能的影响。