Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/opengl/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Opengl 将值列表传递给片段着色器_Opengl_Glsl - Fatal编程技术网

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

Opengl 将值列表传递给片段着色器,opengl,glsl,Opengl,Glsl,我想向片段着色器发送一个值列表。这可能是一个很大的单精度浮点列表(长达数千项)。片段着色器需要随机访问此列表,我希望刷新每个帧上CPU的值 我正在考虑如何做到这一点: 作为数组类型的统一变量(“统一浮点x[10];”)。但这里似乎有一些限制,在我的GPU上发送几百个以上的值非常慢,而且当我希望在运行时更改上限时,我必须在着色器中硬编码上限 作为高度为1、宽度为“我的列表”的纹理,然后使用glCopyTexSubImage2D刷新数据 其他方法?我最近没有跟上GL规范的所有变化,也许有其他专门为此

我想向片段着色器发送一个值列表。这可能是一个很大的单精度浮点列表(长达数千项)。片段着色器需要随机访问此列表,我希望刷新每个帧上CPU的值

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

  • 作为数组类型的统一变量(“统一浮点x[10];”)。但这里似乎有一些限制,在我的GPU上发送几百个以上的值非常慢,而且当我希望在运行时更改上限时,我必须在着色器中硬编码上限

  • 作为高度为1、宽度为“我的列表”的纹理,然后使用glCopyTexSubImage2D刷新数据

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


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

    我认为可能不是第一。。着色器制服的寄存器数量有限,因卡而异。您可以查询GL_MAX_FRAGMENT_UNIFORM_组件以了解您的限制。在较新的卡上,它的数量达到了数千张,例如一张Quadro FX 5500显然有2048张。(http://www.nvnews.net/vbulletin/showthread.php?t=85925). 这取决于您希望它在什么硬件上运行,以及您可能还希望向着色器发送什么其他制服

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

    我不确定第3点,但我建议可以看看UAV(无序访问视图),尽管我认为这只是DirectX,没有合适的openGL等价物。我认为openGL有一个nVidia扩展,但同样地,您将自己限制在一个非常严格的最低规范中


    向片段着色器传递1000个数据项不太可能是解决问题的最佳解决方案。。如果你提供了更多关于你想要实现的目标的细节,你可能会得到其他的建议?

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

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

    但我认为纹理缓冲区是解决你问题的最佳选择。为了获得更准确的信息,您还可以查看相应的


    编辑:作为对Nicol关于的评论的回应,您还可以对两者进行一些比较。我仍然倾向于TBO,但无法真正解释原因,只是因为我认为它在概念上更适合。但也许Nicol可以提供一个更深入的答案。目前有4种方法可以做到这一点:标准1D纹理、缓冲纹理、统一缓冲区和着色器存储缓冲区

    一维纹理 使用此方法,可以使用
    glTex(Sub)Image1D
    用数据填充1D纹理。因为您的数据只是一个浮点数组,所以您的数据应该是
    GL\u R32F
    。然后通过一个简单的
    texelFetch
    调用在着色器中访问它
    texelFetch
    获取texel坐标(因此得名),并关闭所有过滤。所以你只得到一个特克斯

    注:
    texelFetch
    为3.0+。如果要使用以前的GL版本,则需要将大小传递给着色器并手动规格化纹理坐标

    这里的主要优点是兼容性和紧凑性。这将适用于GL 2.1硬件(使用符号)。您不必使用
    GL_R32F
    格式;您可以使用
    GL_R16F
    half float。或者
    GL_R8
    ,如果您的数据对于规范化字节来说是合理的。尺寸对于整体性能来说意义重大

    主要缺点是尺寸限制。您只能拥有最大纹理大小的1D纹理。在GL 3.x级硬件上,该值约为8192,但保证不低于4096

    统一缓冲区对象 其工作方式是在着色器中声明统一块:

    layout(std140) uniform MyBlock
    {
      float myDataArray[size];
    };
    
    然后在着色器中访问该数据,就像访问数组一样

    回到C/C++/etc代码中,创建一个缓冲区对象并用浮点数据填充它。然后,您可以将该缓冲区对象与
    MyBlock
    统一块相关联

    这种技术的主要优点是速度和语义。速度取决于实现的方式
    vec4 position = texelFetch(myDataArray, 2*index);
    vec4 color = texelFetch(myDataArray, 2*index + 1);