将值列表传递给片段着色器

时间:2011-10-31 14:17:18

标签: opengl glsl

我想将一个值列表发送到片段着色器中。它是一个可能很大(几千个项目长)的单精度浮标列表。片段着色器需要随机访问此列表,我想在每个帧上刷新CPU的值。

我正在考虑如何做到这一点:

  1. 作为数组类型的统一变量(“uniform float x [10];”)。但是这里似乎有限制,在我的GPU上发送超过几百个值非常慢,而且当我宁愿在运行时更改它时,我还必须对着色器中的上限进行硬编码。

  2. 作为高度为1且列表宽度的纹理,然后使用glCopyTexSubImage2D刷新数据。

  3. 其他方法?我最近没有跟上GL规范中的所有变化,也许还有一些专门为此目的设计的方法?

4 个答案:

答案 0 :(得分:124)

答案 1 :(得分:6)

这听起来像texture buffer objects的一个很好的用例。这些与常规纹理没有多大关系,基本上允许您在着色器中以简单的线性数组的形式访问缓冲区对象的内存。它们类似于1D纹理,但不会被过滤,只能通过整数索引访问,这听起来就像您将其称为值列表时需要执行的操作。它们还支持比1D纹理更大的尺寸。为了更新它,您可以使用标准缓冲区对象方法(glBufferDataglMapBuffer,...)。

但另一方面,他们需要使用GL3 / DX10硬件,我认为它甚至已经成为OpenGL 3.1的核心。如果您的硬件/驱动程序不支持它,那么您的第二个解决方案将是选择的方法,而是使用1D纹理而不是宽度x 1 2D纹理)。在这种情况下,您还可以使用非平面2D纹理和一些索引魔法来支持大于最大纹理大小的列表。

但我认为纹理缓冲区是您问题的完美匹配。要获得更准确的见解,您还可以查看相应的extension specification

编辑:为了回应Nicol对uniform buffer objects的评论,您还可以查看here对这两者的一些比较。我仍然倾向于TBO,但不能说明原因,只是因为我认为它更符合概念。但也许尼科尔可以提供一些更深入了解此事的人。

答案 2 :(得分:5)

一种方法是使用像你提到的统一数组。另一种方法是使用一维“纹理”。查找GL_TEXTURE_1D和glTexImage1D。我个人更喜欢这种方式,因为你不需要如你所说的那样在着色器代码中硬编码数组的大小,而且opengl已经具有用于在GPU上上传/访问1D数据的内置函数。

答案 3 :(得分:1)

我想说可能不是第1号..你的着色器制服的注册数量有限,因卡而异。您可以查询GL_MAX_FRAGMENT_UNIFORM_COMPONENTS以查找限制。在较新的卡上,它会遇到数千个,例如显然,Quadro FX 5500有2048。 (http://www.nvnews.net/vbulletin/showthread.php?t=85925)。这取决于您希望它运行的硬件,以及您可能想要发送到着色器的其他制服。

根据您的要求,可以使第2号工作。很抱歉这里含糊不清,希望其他人可以给你一个更精确的答案,但你必须明确你在旧的着色器模型卡中进行了多少纹理调用。它还取决于您希望每个片段执行多少纹理读取,您可能不希望再次尝试读取每个片段的1000个元素,具体取决于着色器模型和性能要求。您可以将值打包到纹理的RGBAs中,每次纹理调用可以读取4次,但是随机访问是一项要求,这可能对您没有帮助。

我不确定3号,但我建议可能会看UAV(无序访问视图),虽然我认为这只是DirectX,没有像样的openGL。我认为有一个针对openGL的nVidia扩展,但是你再次将自己限制在一个非常严格的最低规范。

将1000个数据项传递到您的片段着色器不太可能是您问题的最佳解决方案。也许如果您提供了有关您尝试实现的内容的更多详细信息,您可能会获得其他建议吗?