画出一堆由CUDA / OpenCL生成的元素?

时间:2012-05-22 07:04:41

标签: opengl cuda

我是图形编程的新手,需要为我们正在创建的演示添加渲染后端。我希望你们能指出我正确的方向。

短版:有没有办法向OpenGL发送不同元素的数据数组,而不必明确地为每个元素发出绘图命令?

长版本:我们有一个CUDA程序(最终将是OpenCL),它为我们计算了一堆对象的一堆数据。然后,我们需要使用例如OpenGL渲染这些对象。

CUDA内核可以生成我们的顶点,并且使用OpenGL互操作,它可以将它们推送到OpenGL VBO中,而不必将数据传输回主机设备内存。但问题是我们有一堆(超过一百万是我们的目标)不同的对象。看来我们最好的选择是分配一个VBO并将每个对象的顶点放入其中。然后我们可以调用glDrawArrays,其中包含VBO中每个元素的偏移量和长度。

然而,每个对象可能有一个可变数量的顶点(虽然场景中的总顶点可以有界。)我想避免转移一个起始索引和长度列表来自CUDA - >每帧都有CPU,特别是考虑到这些绘图命令会直接返回GPU。

有没有办法打包带有数据的缓冲区,这样我们只能发出一次OpenGL调用来渲染缓冲区,它可以从缓冲区中渲染出许多不同的元素?

(希望我也提供了足够的信息来避免XY问题。)

2 个答案:

答案 0 :(得分:3)

一种方法是远离将这些理解为单个对象,并使它们成为使用单个绘制调用绘制的单个大对象。问题是,哪些数据可以区分对象,这意味着您在对glDrawArrays/glDrawElements的各个调用之间改变了什么?

如果它是一种简单的东西,比如一种颜色,那么提供额外的每顶点属性可能会更容易。这样,您可以使用单个绘制调用将所有对象渲染为单个大对象,其中单个子对象(实际上现在仅在概念上存在)正确着色。额外属性的内存成本可能非常值得。

如果它有点复杂(比如纹理),你仍然可以使用额外的每顶点属性对其进行索引,或者是纹理数组的索引(因为CUDA应该支持纹理数组) / OpenCL-able硬件)或纹理坐标到单个大纹理的特定子区域(所谓的纹理图集)。

但是如果这些对象之间的差异更复杂,作为不同的着色器或其他东西,您可能真的需要渲染单个对象并进行单独的绘制调用。但是你仍然不需要进行CPU的往返。使用ARB_draw_indirect扩展(自GL 4.0以来是核心,我认为,但可能在GL 3硬件(以及CUDA / CL硬件)上支持,但不知道)您可以获取参数来自附加缓冲区的glDrawArrays/glDrawElements调用(您可以像其他任何GL缓冲区一样使用CUDA / CL编写)。因此,您可以在GPU上组合每个单独对象的偏移长度信息,并将它们存储在单个缓冲区中。然后你将glDrawArraysIndirect循环偏移到这个单一的draw-indirect-buffer中(各个对象之间的偏移现在是常量)。


但是,如果发出多个绘制调用的唯一原因是您希望将对象渲染为单个GL_TRIANGLE_STRIPGL_TRIANGLE_FAN s(或者,请注意,GL_POLYGON s),你可能想重新考虑使用一堆GL_TRIANGLES,这样你就可以在一次绘制调用中渲染所有对象。使用三角形条带的(可能)时间和内存节省可能会因多次绘制调用的开销而超出,特别是在渲染许多小三角形条带时。如果你真的想要使用条带或扇子,你可能想要引入退化三角形(通过重复顶点)将它们彼此分开,即使用单个绘制调用绘制也是如此。或者您可以查看GL 3.1引入的glPrimitiveRestartIndex函数。

答案 1 :(得分:0)

可能不是最佳,但你可以在你的整个缓冲区上制作一个glDrawArray ......

  • 如果使用GL_TRIANGLES,则可以用零填充缓冲区,并在内核中只写入所需的顶点。这样,缓冲区的“空”区域将被绘制为0区域多边形(=退化多边形 - >根本不绘制)
  • 如果您使用GL_TRIANGLE_STRIP,您也可以这样做,但您必须复制第一个顶点才能在(0,0,0)和网格之间形成假三角形。

这看起来有点矫枉过正,但是:   - 无论如何,你必须能够处理尽可能多的顶点   - 简并三角形不使用填充,因此它们几乎是自由的(尽管仍然计算了顶点着色器)

一个可能更好的解决方案是使用glDrawElements:在你的内核中,你还为整个缓冲区生成一个索引列表,它将能够完全跳过缓冲区的区域。