OpenGL纹理单元与常规缓冲区和uniform的背后推理是什么?

6
我对OpenGL API非常陌生,最近刚刚了解到纹理及其使用方法。生成的纹理缓冲区不像常规uniform变量一样绑定,而是使用glActiveTexture命令来绑定,而不是像我们使用glUniform将纹理直接传递给着色器。这种惯例背后的原因是什么?
我唯一能想到的原因是为了充分利用显卡的处理能力和纹理处理能力,而不仅仅是直接绑定缓冲区。这是否正确,还是这只是API实现的方式?
官方wiki上没有给出任何推理,只是说这很奇怪:“在OpenGL中绑定纹理有点奇怪” https://www.khronos.org/opengl/wiki/Texture

1
相关但不重复 - Borgleader
我会看一下,看看它是否回答了我的问题,谢谢。没看到那个。 - Timothy
如果您使用“直接状态访问”(DSA),API 就会更有意义。假设您正在使用 GL 核心 4.5 或更高版本。 - Robinson
2个回答

8
您的问题有两种解释方式。
“为什么我们将纹理绑定到上下文而不是着色器中?”
因为这样做将使多个着色器使用相同纹理变得不必要地困难。请注意,几乎没有任何图形API直接将纹理附加到程序中。无论是任何版本的D3D,还是Metal,甚至是Vulkan。
纹理是着色器使用的资源。但它们不是着色器的一部分。
“为什么我们要将纹理与普通值数组区别对待?”
在现代OpenGL中,着色器可以访问几种不同类型的资源:UBO、SSBO、纹理和图像。每一种资源最终代表了图形硬件的一个潜在不同部分。
存储块不仅仅是一个可以更大的统一块。存储缓冲区表示着色器执行全局内存访问,而统一块通常直接复制到着色器执行单元中。在后一种情况下,访问它们的数据要快得多,但这也意味着您受限于这些执行单元可以拥有的存储量。
现在,这并不适用于所有硬件(AMD的GCN硬件将这两种硬件处理方式几乎相同,这就是为什么他们的UBO限制如此之大)。但对于许多硬件来说,这是真实的。
纹理更加复杂,因为实现需要能够以性能优化的方式存储它们的数据。因此,纹理存储格式是不透明的。它们甚至在名义上的低级别API(例如Vulkan)中也是不透明的。当然,线性格式确实存在,但是实现未必允许您从中读取。
所以,纹理不仅仅是常量数组。

谢谢。这个回答很好。 :) - Timothy

1

你正在比较两个完全不同的东西。

纹理对象可以(以某种方式)与缓冲区对象进行比较。纹理通过 glActiveTextureglBindTexture 的组合绑定到纹理单元,而缓冲区则通过类似的 glBindBuffer 绑定。

纹理采样器 uniform 是着色器中的一个 uniform,因此应该与其他 uniform 进行比较。这个采样器是通过 glUniform1i 调用设置的。


采样器是由统一调用设置的,它们从纹理单元获取纹理数据。明白了。但是,这样做的原因是什么,而不是通常发送到着色器的像素颜色(纹理)的巨大数组?硬件受益? - Timothy
@Timothy:“但是,为什么要这样做呢,而不是将像素颜色(纹理)的巨大数组通常发送到着色器?”你所说的“通常”是什么意思?没有一种“正常”的方法可以将“巨大的像素颜色数组”发送到着色器。大多数纹理很容易超过统一数组甚至UBO的存储限制。 - Nicol Bolas
@NicolBolas大型纹理可能会超出限制,但较小的纹理不会。所以你的意思是答案仅仅涉及存储大小的考虑? - Timothy
@Timothy:不,我的意思是这个问题没有意义。纹理不是均匀数组,因此以访问均匀变量的方式访问纹理是没有意义的。 - Nicol Bolas

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