将一个纹理绑定到两个不同的统一采样器

Posted

技术标签:

【中文标题】将一个纹理绑定到两个不同的统一采样器【英文标题】:Bind one texture to two different uniform samplers 【发布时间】:2016-08-14 20:25:20 【问题描述】:

是否可以将一个纹理绑定到 openGL 中的两个(或多个)不同的统一采样器? 当使用两种不同的纹理进行渲染时,它是这样的:

着色器:

uniform sampler2D texture1;
uniform sampler2D texture2;
....

客户:

//Initial shader program setup.
glLinkProgram(program);

GLuint texture1Loc = glGetUniformLocation(program, "texture1");
GLuint texture2Loc = glGetUniformLocation(program, "texture2");

glUseProgram(program);
glUniform1i(texture1Loc, 0); //Texture unit 0 is for texture1 sampler.
glUniform1i(texture2Loc, 1); //Texture unit 1 is for texture2 sampler.

//When rendering an object with this program.
glActiveTexture(GL_TEXTURE0 + 0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, texture2);

//Render stuff
glDraw*();

但是当我尝试将一个纹理对象绑定到两个不同的纹理单元时,似乎首先绑定的单元保持未绑定:

glActiveTexture(GL_TEXTURE0 + 0);
glBindTexture(GL_TEXTURE_2D, texture1); // bind texture1
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, texture1); // bind texture1 - again, but to another unit

当然可以为两个采样器设置相同的单位,但有时我也想将我的着色器用于不同的纹理 - 不仅为两个采样器设置相同的纹理对象。

glUniform1i(texture1Loc, 0); //Texture unit 0 is for texture1 sampler.
glUniform1i(texture2Loc, 0); //Texture unit 0 is for texture2 sampler ( thesame unit ).

这个解决方案实际上效果很好,但它不符合我所描述的需求。 也可以在绑定之前更改采样器的纹理单元,但这对我来说似乎不是一个干净的解决方案。

glUniform1i(texture1Loc, 0); //Texture unit 0 is for texture1 sampler.
glActiveTexture(GL_TEXTURE0 + 0);
glBindTexture(GL_TEXTURE_2D, texture1);


glUniform1i(texture2Loc, 1); //Texture unit 1 is for texture2 sampler
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, texture2);

....

glUniform1i(texture1Loc, 0); //Texture unit 0 is for texture1 sampler.
glUniform1i(texture2Loc, 0); //Texture unit 0 is for texture2 sampler.
glActiveTexture(GL_TEXTURE0 + 0);
glBindTexture(GL_TEXTURE_2D, texture1);

有什么解决办法吗?也许第一种方法是正确的,但我做错了什么?是否可以将一个纹理绑定到多个单元?

【问题讨论】:

您知道(片段?)着色器中实际使用制服的部分... 丢失了吗?如果不了解制服在编译和链接的程序中是如何使用的,就很难诊断出您的问题。这意味着显示着色器的其余部分实际上很重要,并且因为一些 GLSL 编译器在两遍中完成工作,其他着色器阶段也是如此。如果编译器以某种方式确定代码路径已死,它将开始删除/替换常量表达式。 【参考方案1】:

将相同的纹理绑定到两个不同的纹理单元,并在着色器中使用这两个纹理单元,应该非常好。您的代码中存在不同的问题,或者您正在使用的 OpenGL 实现中存在问题。

我能找到的唯一一些相关的错误情况如下,在 OpenGL 3.3 规范的第 82 页,在“2.11 顶点着色器”部分下的“验证”小节中:

此错误由将顶点传输到 GL 的任何命令生成,如果:[..] 当前程序对象中的任何两个活动采样器属于不同类型,但引用相同的纹理图像单元,[..]

但这不是您正在做的事情,而且我从未见过任何指定的内容会阻止您将相同的纹理绑定到多个纹理单元。如果存在这样的限制,我希望它与上面引用的部分位于同一部分,并且没有指定这样的内容。

【讨论】:

此外,这样的限制会使采样器对象的使用毫无意义(相同的纹理,绑定在多个纹理单元中,每个单元都有不同的采样器处于活动状态)。 我已经检查了 OpenGL 和 GLSL 错误 - 没有,它仍然按照描述的那样工作。我在 Internet 和 OGL 文档上都找不到有关此示例的任何信息。我在 Windows 7 x64 上使用 OpenGL 3.3.11672、GLSL 330 和 Radeon 4650m。 您有其他配置可以试用吗?尤其是使用不同供应商的 GPU? @Krzycho:包括在绘制任何东西之前调用(几乎未知的)glValidateProgram 函数(即设置所有状态),然后检查验证状态和信息日志?跨度> @peppe:谢谢你的帮助,是的 - glValidateProgram 给了我Validation successful

以上是关于将一个纹理绑定到两个不同的统一采样器的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL均匀采样器2D具有相同的图像

绑定 OpenGL 纹理采样器

使用纹理数组时,为啥我不必将采样器绑定到着色器?

多采样渲染到纹理

Opengl 和 Webgl:从附加到当前帧缓冲区的纹理中采样

金属着色器纹理读取与示例