OpenGL4.5 - 绑定多个纹理和采样器

OpenGL4.5 - bind multiple textures and samplers

我正在尝试了解 OpenGL 4.5 中的纹理、纹理单元和采样器。我附上了一张我想弄清楚的照片。我认为在我的示例中一切都是正确的,但我不太确定右侧带有问号的一维采样器。

所以,我知道 OpenGL 提供了许多纹理 units/binding 点,纹理和采样器可以在这些点上绑定,以便它们一起工作。

这些绑定点中的每一个都可以支持每个纹理目标之一(在我的例子中,我将目标 GL_TEXTURE_2DGL_TEXTURE_1D 绑定到绑定点 0,另一个 GL_TEXTURE_2D 到绑定点 1).

此外,采样器可以以几乎相同的方式绑定到这些绑定点(我已将 2D 采样器绑定到图片中的绑定点 0)。

执行这些操作的函数是glBindTextureUnitglBindSampler

我最初的想法是将 1D 采样器也绑定到绑定点 0,并在着色器区域根据绑定点和采样器的类型进行匹配:

layout (binding = 0) uniform sampler1D tex1D;
layout (binding = 0) uniform sampler2D tex2D;

引用来源:

Each texture image unit supports bindings to all targets. So a 2D texture and an array texture can be bound to the same image unit, or different 2D textures can be bound in two different image units without affecting each other. So which texture gets used when rendering? In GLSL, this depends on the type of sampler that uses this texture image unit.

但我发现了以下语句:

[..] sounds suspiciously like you can use the same texture image unit for different samplers, as long as they have different texture types. Do not do this. The spec explicitly disallows it; if two different GLSL samplers have different texture types, but are associated with the same texture image unit, then rendering will fail. Give each sampler a different texture image unit.

所以,我的问题是,如果最终 单个 采样器将绑定到同一绑定点,则将不同的纹理目标绑定到同一绑定点的目的是什么绑定点,逼着你选?

我引用的信息:https://www.khronos.org/opengl/wiki/Texture#Texture_image_units

那么为什么会这样呢?嗯...

曾几何时,没有纹理单元(这就是为什么 glActiveTexture 是一个独立于 glBindTexture 的函数)。事实上,在 OpenGL 1.0 中甚至没有纹理 objects。但是仍然需要有不同种类的纹理。您仍然需要能够为 2D 纹理和 3D 纹理创建数据。所以他们提出了纹理目标区分,他们使用 glEnables 来确定在渲染操作中将使用哪个目标。

当纹理对象出现在GL 1.1中时,他们必须决定纹理对象和目标之间的关系。他们决定,一旦一个对象绑定到一个目标,它就与该目标永久关联。由于前面提到的需要有多个不同类型的纹理,使用旧的启用功能,决定每个目标代表一个单独的对象绑定点。他们让你重复 glBindTexture 中的绑定点,这样代码的 reader 就会清楚你正在干扰哪个绑定点的数据。

切换到 OpenGL 1.2,此时出现了多纹理。所以现在他们需要你能够绑定同一目标的多个纹理,但绑定到不同的 "units"。但他们无法更改 glBindTexture 以指定特定单位;那将是一个向后不兼容的更改。

现在,他们本可以彻底改进纹理的工作方式,创建专门用于多纹理等的新绑定函数。但是 OpenGL ARB 喜欢向后兼容;他们喜欢让旧的 API 函数起作用,不管结果 API 是什么样子。因此,他们决定一个纹理单元将是整个 绑定,每个集都有一个启用状态,说明要使用哪个目标。您可以使用 glActiveTexture.

在单位之间切换

当然,一旦着色器出现,你就会看到这一切发生了怎样的变化。启用状态成为着色器中的采样器类型。所以现在没有明确的代码描述启用了哪个纹理目标;这只是着色器的东西。所以他们必须制定一条规则,规定如果两个采样器类型不同,则不能使用相同的单元。

这就是为什么每个纹理单元都有多个独立的绑定点:OpenGL 对向后兼容性的承诺。

最好忽略此功能的存在。绑定您的特定着色器需要的正确纹理。所以专注于使用这些功能,不要担心您可能将两个纹理绑定到同一个目标。如果你想确定你没有不小心使用了错误的纹理,你可以使用 glBindTexturesglBindTextureUnit 纹理名称为 0,这将解除绑定特定纹理单元中的所有目标).

假设您有两个 GLSL 程序:

在程序 A 中:

uniform sampler1D progA_sampler1D;
uniform sampler2D progA_sampler2D;

在程序 B 中:

uniform sampler1D progB_sampler1D;
uniform sampler2D progB_sampler2D;

并且您有多个纹理名称为 text1D_1、text1D_2、text1D_3、... text2D_1、text2D_2 等

现在假设您希望 progA 从 text1D_1 和 text2D_1 中采样,而 progB 从 text1D_2 和 text2D_2 中采样

您已经知道每个采样器必须与一个纹理单元相关联,而不是与一个纹理名称相关联。 我们不能对两个采样器 progA_sampler1DprogA_sampler2D 使用相同的纹理单元

第一个选项: 四个纹理单元

glUseProgram(progA);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_1D, text1D_1);
glUniform1i(locationProgA_forSampler1D, 1); // Not glUniform1i(locationProgA_forSampler1D, GL_TEXTURE0 + 1);
glActiveTexture(GL_TEXTURE0 + 2);
glBindTexture(GL_TEXTURE_2D, text2D_1);
glUniform1i(locationProgA_forSampler2D, 2);

glUseProgram(progB);
glActiveTexture(GL_TEXTURE0 + 3);
glBindTexture(GL_TEXTURE_1D, text1D_2);
glUniform1i(locationProgA_forSampler1D, 3);
glActiveTexture(GL_TEXTURE0 + 4);
glBindTexture(GL_TEXTURE_2D, text2D_2);
glUniform1i(locationProgA_forSampler2D, 4);

第二个选项:两个纹理单元

glUseProgram(progA);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_1D, text1D_1);
glUniform1i(locationProgA_forSampler1D, 1);
glActiveTexture(GL_TEXTURE0 + 2);
glBindTexture(GL_TEXTURE_2D, text2D_1);
glUniform1i(locationProgA_forSampler2D, 2);

glUseProgram(progB);
glActiveTexture(GL_TEXTURE0 + 2);
glBindTexture(GL_TEXTURE_1D, text1D_2);
glUniform1i(locationProgA_forSampler1D, 2);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, text2D_2);
glUniform1i(locationProgA_forSampler2D, 1);

请注意,单元GL_TEXTURE0 + 1绑定了两个不同类型的纹理text1D_1和text2D_2。
以同样的方式GL_TEXTURE0 + 2绑定了两个纹理,类型为GL_TEXTURE_2DGL_TEXTURE_1D

错误选项:两个纹理单元

glUseProgram(progA);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_1D, text1D_1);
glUniform1i(locationProgA_forSampler1D, 1);
glActiveTexture(GL_TEXTURE0 + 2);
glBindTexture(GL_TEXTURE_2D, text2D_1);
glUniform1i(locationProgA_forSampler2D, 2);

glUseProgram(progB);
glActiveTexture(GL_TEXTURE0 + 1);
//Next is wrong: two textures (text1D_1 and text1D_2) of same type GL_TEXTURE_1D
glBindTexture(GL_TEXTURE_1D, text1D_2);
glUniform1i(locationProgA_forSampler1D, 1);
glActiveTexture(GL_TEXTURE0 + 2);
glBindTexture(GL_TEXTURE_2D, text2D_2);  //Wrong: two textures of same type GL_TEXTURE_2D
glUniform1i(locationProgA_forSampler2D, 2);