【问题标题】:OpenGL4.5 - bind multiple textures and samplersOpenGL4.5 - 绑定多个纹理和采样器
【发布时间】:2017-12-27 06:26:27
【问题描述】:

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

所以,我知道 OpenGL 提供了许多纹理单元/绑定点,可以在其中绑定纹理和采样器,以便它们一起工作。

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

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

执行这些操作的函数是glBindTextureUnitglBindSampler

我最初的想法是将一维采样器也绑定到绑定点 0,然后在着色器领域根据绑定点和采样器的类型进行匹配:

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

引用来源:

每个纹理图像单元都支持绑定到所有目标。 所以是 2D 纹理和数组纹理可以绑定到同一个图像单元,或者 不同的 2D 纹理可以绑定在两个不同的图像单元中 互不影响。那么什么时候使用哪个纹理 渲染?在 GLSL 中,这取决于使用它的采样器的类型 纹理图像单元。

但我找到了以下语句:

[..] 听起来很可疑,就像您可以使用相同的纹理图像单元 对于不同的采样器,只要它们具有不同的纹理类型。 不要这样做。规范明确禁止它;如果两个不同 GLSL 采样器具有不同的纹理类型,但与 相同的纹理图像单元,则渲染将失败。 给每个 采样不同的纹理图像单元。

所以,我的问题是,如果最终将 单个 采样器绑定到该绑定点,那么将不同的纹理目标绑定到同一个绑定点的目的是什么,这会迫使您选择?

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

【问题讨论】:

    标签: c++ opengl textures texture-mapping opengl-4


    【解决方案1】:

    那么为什么会存在呢?嗯……

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

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

    当多纹理出现时,切换到 OpenGL 1.2。因此,现在他们需要您能够将同一目标的多个纹理绑定到不同的“单元”。但是他们不能改变glBindTexture 来指定一个特定的单位;这将是一个向后不兼容的更改。

    现在,他们可以彻底改变纹理的工作方式,创建专门用于多重纹理等的新绑定功能。但是 OpenGL ARB 喜欢向后兼容;他们喜欢让旧的 API 函数正常工作,不管生成的 API 是什么样的。所以相反,他们决定纹理单元将是一个完整的 set 绑定,每个集合都有一个启用状态,说明哪个目标是要使用的目标。你用glActiveTexture在单位之间切换。

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

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

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

    【讨论】:

    • 你能展示一个 OpenGL 3.3 的多绑定示例吗? glBindTexturesglBindTextureUnit 仅适用于 OGL4.5。今天仍有大量硬件不允许使用该版本。
    • @Ripi2:从字面上看,标题的第一个单词是“OpenGL4.5”。很明显,OP 询问的是 OpenGL 版本 4.5,所以没有必要提供 3.3 的替代方案。另外,这个问题被标记为opengl-4,所以3.3在这里也没有意义。
    • @Ripi2:此外,在 GL 4.4 的核心中添加了多绑定。它是supported on some 3.3 class hardware too 的扩展名。甚至 ARB_DSA has some support on 3.3 hardware.
    • @NicolBolas 感谢您的回答。因此,简而言之,只连接到一个单元纹理 a) 单个纹理和 b) 单个采样器,两者都必须在维度上匹配。那是对的吗?我得到了 4.5 Programming Guide 并且我正在努力坚持下去(实际上它甚至没有提到glActiveTexture),并且glBindTextureUnit 的描述并没有说它为给定的纹理单元取消绑定所有其他目标(你在第一段中提到的第二个效果)。
    • @CarlosRomero: glBindTexturesglBindTextureUnit 做的事,只是一次处理多个纹理。
    【解决方案2】:

    假设您有两个 GLSL 程序:

    在 progA 中:

    uniform sampler1D progA_sampler1D;
    uniform sampler2D progA_sampler2D;
    

    在 progB 中:

    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);
    

    【讨论】:

    • glUniform1i(locationProgA_forSampler1D, GL_TEXTURE0 + 1); 这不是它的工作原理。即使我们忽略了这个错误,你所说的也是你不应该做的事情。这是非常容易出错的代码。
    • @NicolBolas 感谢您指出该错误。现在修好了。当然 Second option 容易出错。这只是对OP关于那些明显矛盾的句子的解释。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-10
    • 1970-01-01
    • 1970-01-01
    • 2015-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多