我是图形编程的新手,需要为我们正在创建的演示添加渲染后端。我希望你们能指出我正确的方向。
短版:有没有办法向OpenGL发送不同元素的数据数组,而不必明确地为每个元素发出绘图命令?
长版本:我们有一个CUDA程序(最终将是OpenCL),它为我们计算了一堆对象的一堆数据。然后,我们需要使用例如OpenGL渲染这些对象。
CUDA内核可以生成我们的顶点,并且使用OpenGL互操作,它可以将它们推送到OpenGL VBO中,而不必将数据传输回主机设备内存。但问题是我们有一堆(超过一百万是我们的目标)不同的对象。看来我们最好的选择是分配一个VBO并将每个对象的顶点放入其中。然后我们可以调用glDrawArrays,其中包含VBO中每个元素的偏移量和长度。
然而,每个对象可能有一个可变数量的顶点(虽然场景中的总顶点可以有界。)我想避免转移一个起始索引和长度列表来自CUDA - >每帧都有CPU,特别是考虑到这些绘图命令会直接返回GPU。
有没有办法打包带有数据的缓冲区,这样我们只能发出一次OpenGL调用来渲染缓冲区,它可以从缓冲区中渲染出许多不同的元素?
(希望我也提供了足够的信息来避免XY问题。)
答案 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_STRIP
或GL_TRIANGLE_FAN
s(或者,请注意,GL_POLYGON
s),你可能想重新考虑使用一堆GL_TRIANGLES
,这样你就可以在一次绘制调用中渲染所有对象。使用三角形条带的(可能)时间和内存节省可能会因多次绘制调用的开销而超出,特别是在渲染许多小三角形条带时。如果你真的想要使用条带或扇子,你可能想要引入退化三角形(通过重复顶点)将它们彼此分开,即使用单个绘制调用绘制也是如此。或者您可以查看GL 3.1引入的glPrimitiveRestartIndex
函数。
答案 1 :(得分:0)
可能不是最佳,但你可以在你的整个缓冲区上制作一个glDrawArray ......
这看起来有点矫枉过正,但是: - 无论如何,你必须能够处理尽可能多的顶点 - 简并三角形不使用填充,因此它们几乎是自由的(尽管仍然计算了顶点着色器)
一个可能更好的解决方案是使用glDrawElements:在你的内核中,你还为整个缓冲区生成一个索引列表,它将能够完全跳过缓冲区的区域。