通过 Compute Shader 与 Screen Quad 进行光线追踪
Ray tracing via Compute Shader vs Screen Quad
我最近在寻找通过 opengl 教程进行的光线追踪。大多数教程更喜欢计算着色器。我想知道为什么他们不直接渲染到纹理,然后将纹理渲染到屏幕上作为四边形。
计算着色器方法相对于屏幕四边形的优缺点是什么?
简短回答:因为计算着色器为您提供了更有效的工具来执行复杂的计算。
长答案:
也许他们提供的最大优势(在跟踪的情况下)是能够精确控制 如何 工作在 GPU 上执行。当您追踪复杂场景时,这一点很重要。如果您的场景是微不足道的(例如 Cornell Box),那么差异可以忽略不计。一整天都在片段着色器中跟踪一些球体。检查 http://shadertoy.com/ 以见证现代 GPU 和片段着色器可以实现的疯狂。
但是。如果您的场景和阴影非常复杂,您需要 来控制工作的完成方式。渲染一个四边形并在碎片着色器中进行跟踪充其量只会让您的应用程序挂起,而 driver 哭泣,更改其合法名称并移动到世界的另一端......并且在最糟糕的是,让 driver 崩溃。如果单个操作花费的时间太长,许多 drivers 将中止(这在标准用法下几乎不会发生,但当您开始尝试跟踪 1M 多边形场景时会发生得非常快)。
所以你在片段着色器中做了太多的工作......下一个合乎逻辑吗?好的,限制工作量。绘制较小的四边形以控制一次跟踪的屏幕范围。或者使用 glScissor。让工作量越来越小,直到你的 driver 可以处理它。
猜猜我们刚才 re-invented 是什么?计算着色器 工作组 !工作组是计算着色器 控制作业大小 的机制,与 fragment-level hackery(当我们处理这种复杂的任务)。现在我们可以很自然地控制我们发送多少光线,而且我们可以做到这一点而不必 tightly-coupled 到 screen-space。对于简单的示踪剂,这增加了不必要的复杂性。对于 'real' 一个,这意味着我们可以轻松地在抖动网格上进行 sub-pixel 光线投射以进行 AA,如果我们愿意的话,每个像素的大量光线投射可以用于路径追踪,等等
对性能有用的计算着色器的其他功能,industrial-strength 跟踪器:
- 线程组之间的共享内存(允许,例如,数据包跟踪,其中 spatially-coherent 射线的整个数据包同时被追踪以利用记忆连贯性和与附近光线通信的能力)
- Scatter Writes 允许计算着色器写入任意图像位置(注意:图像和纹理在细微方面有所不同,但优势仍然相关);您不再需要直接从已知像素位置进行追踪
一般来说,现代 GPU 的架构旨在使用计算更自然地支持此类任务。就个人而言,我已经使用 MLT、kd-tree 加速和许多其他 computationally-expensive 技术(PT 已经非常昂贵)编写了一个 real-time 渐进路径跟踪器。我试图尽可能长时间地留在片段着色器/full-screen 四边形中。一旦我的场景复杂到需要加速结构,我的 driver 就开始窒息,无论我使用什么 hackery。我 re-implemented 在 CUDA 中(与计算不完全相同,但利用相同的基本 GPU 架构进步),并且一切都与世界相得益彰。
如果您真的想深入了解,请浏览此处的第 3.1 节:https://graphics.cg.uni-saarland.de/fileadmin/cguds/papers/2007/guenther_07_BVHonGPU/Guenter_et_al._-_Realtime_Ray_Tracing_on_GPU_with_BVH-based_Packet_Traversal.pdf。坦率地说,这个问题的 最佳 答案将是对 GPU micro-architecture 的广泛讨论,而我根本没有资格给出这个答案。查看像上面这样的现代 GPU 跟踪论文会让您了解性能考虑的深度。
最后一点:在光线追踪复杂场景的上下文中,计算相对于碎片的任何性能优势与光栅化/顶点着色器开销/混合操作开销等完全无关.对于具有复杂阴影的复杂场景,瓶颈是完全在跟踪计算中,正如所讨论的,计算[=48] =] 着色器具有更有效实施的工具。
我要完成 Josh Parnell 的信息。
片段着色器和计算着色器的一个问题是它们都缺乏递归性。
光线追踪器本质上是递归的(是的,我知道总是可以将递归算法转换为非递归算法,但这并不总是那么容易)。
因此,查看问题的另一种方法如下:
代替每个像素 "one thread",一个想法可能是每个路径有一个线程(路径是光线的一部分(在 2 次反弹之间))。
这样一来,您将在 "bunch" 条光线上进行调度,而不是在 "pixel grid" 上进行调度。这样做可以简化光线追踪器的潜在递归性,并避免复杂材料中的发散:
更多信息在这里:
http://research.nvidia.com/publication/megakernels-considered-harmful-wavefront-path-tracing-gpus
我最近在寻找通过 opengl 教程进行的光线追踪。大多数教程更喜欢计算着色器。我想知道为什么他们不直接渲染到纹理,然后将纹理渲染到屏幕上作为四边形。
计算着色器方法相对于屏幕四边形的优缺点是什么?
简短回答:因为计算着色器为您提供了更有效的工具来执行复杂的计算。
长答案:
也许他们提供的最大优势(在跟踪的情况下)是能够精确控制 如何 工作在 GPU 上执行。当您追踪复杂场景时,这一点很重要。如果您的场景是微不足道的(例如 Cornell Box),那么差异可以忽略不计。一整天都在片段着色器中跟踪一些球体。检查 http://shadertoy.com/ 以见证现代 GPU 和片段着色器可以实现的疯狂。
但是。如果您的场景和阴影非常复杂,您需要 来控制工作的完成方式。渲染一个四边形并在碎片着色器中进行跟踪充其量只会让您的应用程序挂起,而 driver 哭泣,更改其合法名称并移动到世界的另一端......并且在最糟糕的是,让 driver 崩溃。如果单个操作花费的时间太长,许多 drivers 将中止(这在标准用法下几乎不会发生,但当您开始尝试跟踪 1M 多边形场景时会发生得非常快)。
所以你在片段着色器中做了太多的工作......下一个合乎逻辑吗?好的,限制工作量。绘制较小的四边形以控制一次跟踪的屏幕范围。或者使用 glScissor。让工作量越来越小,直到你的 driver 可以处理它。
猜猜我们刚才 re-invented 是什么?计算着色器 工作组 !工作组是计算着色器 控制作业大小 的机制,与 fragment-level hackery(当我们处理这种复杂的任务)。现在我们可以很自然地控制我们发送多少光线,而且我们可以做到这一点而不必 tightly-coupled 到 screen-space。对于简单的示踪剂,这增加了不必要的复杂性。对于 'real' 一个,这意味着我们可以轻松地在抖动网格上进行 sub-pixel 光线投射以进行 AA,如果我们愿意的话,每个像素的大量光线投射可以用于路径追踪,等等
对性能有用的计算着色器的其他功能,industrial-strength 跟踪器:
- 线程组之间的共享内存(允许,例如,数据包跟踪,其中 spatially-coherent 射线的整个数据包同时被追踪以利用记忆连贯性和与附近光线通信的能力)
- Scatter Writes 允许计算着色器写入任意图像位置(注意:图像和纹理在细微方面有所不同,但优势仍然相关);您不再需要直接从已知像素位置进行追踪
一般来说,现代 GPU 的架构旨在使用计算更自然地支持此类任务。就个人而言,我已经使用 MLT、kd-tree 加速和许多其他 computationally-expensive 技术(PT 已经非常昂贵)编写了一个 real-time 渐进路径跟踪器。我试图尽可能长时间地留在片段着色器/full-screen 四边形中。一旦我的场景复杂到需要加速结构,我的 driver 就开始窒息,无论我使用什么 hackery。我 re-implemented 在 CUDA 中(与计算不完全相同,但利用相同的基本 GPU 架构进步),并且一切都与世界相得益彰。
如果您真的想深入了解,请浏览此处的第 3.1 节:https://graphics.cg.uni-saarland.de/fileadmin/cguds/papers/2007/guenther_07_BVHonGPU/Guenter_et_al._-_Realtime_Ray_Tracing_on_GPU_with_BVH-based_Packet_Traversal.pdf。坦率地说,这个问题的 最佳 答案将是对 GPU micro-architecture 的广泛讨论,而我根本没有资格给出这个答案。查看像上面这样的现代 GPU 跟踪论文会让您了解性能考虑的深度。
最后一点:在光线追踪复杂场景的上下文中,计算相对于碎片的任何性能优势与光栅化/顶点着色器开销/混合操作开销等完全无关.对于具有复杂阴影的复杂场景,瓶颈是完全在跟踪计算中,正如所讨论的,计算[=48] =] 着色器具有更有效实施的工具。
我要完成 Josh Parnell 的信息。
片段着色器和计算着色器的一个问题是它们都缺乏递归性。
光线追踪器本质上是递归的(是的,我知道总是可以将递归算法转换为非递归算法,但这并不总是那么容易)。
因此,查看问题的另一种方法如下:
代替每个像素 "one thread",一个想法可能是每个路径有一个线程(路径是光线的一部分(在 2 次反弹之间))。
这样一来,您将在 "bunch" 条光线上进行调度,而不是在 "pixel grid" 上进行调度。这样做可以简化光线追踪器的潜在递归性,并避免复杂材料中的发散:
更多信息在这里: http://research.nvidia.com/publication/megakernels-considered-harmful-wavefront-path-tracing-gpus