OpenGL 统一缓冲区混淆

6

有人能告诉我Uniform Buffers为什么看起来那么复杂吗?我已经阅读了OpenGL Superbible 5中的部分内容,查看了一些博客上的示例,并阅读了官方规范,但我仍然不理解。

具体来说,所有示例似乎都需要先使用着色器程序才能使用glGetActiveUniformsiv来初始化uniform buffer。我不明白这一点。为什么接口不允许您在不引用着色器程序的情况下定义结构,在链接时对缓冲区/格式进行验证呢?

其次,如果我从一个程序中获取结构布局,并假设该结构布局对使用该组uniform的所有程序都相同,那么结构是否保证具有相同的偏移量、数据大小等?我会这样假设。

第三,我不理解binding points。我必须使用索引调用glBindBufferBase,然后使用块索引和传递给glBindBufferBase的索引调用glUniformBlockBinding。我很难想象这里到底发生了什么。Superbible、规范和我看到的示例都缺乏清晰度。

1个回答

11
  1. 你到底为什么希望这样做呢?个人认为,除非你有严重的数据短缺问题需要每个字节,否则没有理由使用除了std140以外的任何东西。这将使代码更加干净。

    然而,如果你非常坚决地避免使用std140,请继续阅读。

  2. 规范对此进行了详细的解释:一切都在布局限定符中。

    共有3个布局限定符:packedsharedstd140packed意味着实现可以自由安排几乎所有内容。这包括删除当前程序不使用的uniform。因此,布局是实现定义的,并且该布局中的某些uniform可能已被优化掉。

    shared表示实现可以像packed一样自由安排数据。但是,它必须为每个uniform提供存储空间。这使得可以在程序之间共享统一的uniform布局,因此得名sharedshared还要求实现将为一致的定义提供一致的布局。因此,您只需要对一个布局进行查询。

    回答您的第一个问题,如果您愿意,可以创建一个带有shared布局的虚拟程序。您可以仅用于查询uniform块的布局。然后,只要在其他程序中(具有shared布局)布局保持一致,所有布局将是相同的。因此,不需要特殊的API。

    然而,std140意味着uniform块的布局由OpenGL实现明确定义,逐字节地。这隐式地允许共享,因为在此规范下两个完全相同的uniform块将具有相同的布局。并且,由于实现不能优化掉std140布局块中的uniform,所以一切都很完美。

几乎没有理由避免使用 std140,除非你面临着非常、非常严格的内存限制。

  • 这与纹理的机制完全相同。唯一的区别在于,统一块名称本身不是统一变量。

    纹理对象绑定到纹理图像单元,使用glActiveTexture(GL_TEXTURE0 + i);glBindTexture(),其中i是纹理图像单元索引。现在您需要告诉着色器哪个采样器使用该图像单元。但是,OpenGL不允许您直接将名称与索引位置进行关联;您必须将采样器名称转换为索引位置。因此,您可以使用glGetUniformLocation获取特定采样器的统一变量位置。一旦获得了统一变量位置,就可以通过调用glUniform1i(loc, i)将纹理图像单元与该位置关联,其中i是您绑定纹理的纹理图像单元。

    统一缓冲对象绑定到统一缓冲绑定点,使用glBindBufferRange(GL_UNIFORM_BUFFER, i, ...),其中i是统一缓冲绑定点。现在您需要告诉着色器哪个统一块使用该绑定点。但是,OpenGL不允许您直接将名称与索引位置进行关联;您必须将统一块转换为索引位置。因此,您可以使用glGetUniformBlockIndex获取特定统一块的索引。一旦获得了索引,就可以通过调用glUniformBlockBinding(program, index, i)将统一缓冲绑定点与该索引关联,其中i是您绑定统一缓冲的统一缓冲绑定点。

    看到了吗?完全一样。虽然它们使用不同的术语,但从结构上来看,它们是相同的。如果需要图片,可以在这里找到更详细的讨论和图示。


  • 很有用。谢谢。我无需避免使用std140,但对于共享是否需要使用它或者是shared有些困惑。而且规格似乎在呼喊“使用std140效率低下,但如果必须使用请使用它”。不管怎样,我刚刚找到了你提供链接的网站,这确实使事情更加清晰。所以,为了明确,每个使用给定统一块的程序都要调用glUniformBlockBinding,并且该绑定将在程序运行期间保持不变? - Robinson
    @Robinson:是的,统一块绑定是程序状态。这就是为什么它需要一个程序对象 ;) - Nicol Bolas
    @Nicol 很好的解释,我完全明白了。但是glBindTexture(GL_TEXTURE0+i)是什么?我又落伍了还是这是一个打字错误(或者可能是简化)? - Christian Rau
    @NicolBolas,在OpenGL红皮书第8版中,有一个示例直接使用块索引作为绑定点,这正确吗?请参考该书中的2.4示例。 - suitianshi
    是否可以只使用任何统一缓冲区绑定点?如果绑定点已被占用怎么办?如何获取可用绑定点的索引? - martinrhan

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接