如何将绘图调用和采样器值的更改与单个着色器程序正确混合



我正试图在Android的OpenGL ES 2.0中使用一个着色器程序,使用两种不同的纹理绘制两个对象。第一个对象应该具有texture0,而第二个对象必须具有texture1

在碎片着色器中我有:

uniform sampler2D tex;

在java代码中:

int tiu0 = 0;
int tiu1 = 1;
int texLoc = glGetUniformLocation(program, "tex");
glUseProgram(program);
// bind texture0 to texture image unit 0
glActiveTexture(GL_TEXTURE0 + tiu0);
glBindTexture(GL_TEXTURE_2D, texture0);
// bind texture1 to texture image unit 1
glActiveTexture(GL_TEXTURE0 + tiu1);
glBindTexture(GL_TEXTURE_2D, texture1);
glUniform1i(texLoc, tiu0);
// success: glGetError returns GL_NO_ERROR, glGetUniformiv returns 0 for texLoc
drawFirstObject(); // should have texture0
glUniform1i(texLoc, tiu1);
// success: glGetError returns GL_NO_ERROR, glGetUniformiv returns 1 for texLoc
drawSecondObject(); // should have texture1

在安卓2.3.3的三星Galaxy Ace上运行,两个对象都有相同的texture0。类似的代码可以在我的台式机OpenGL 2.0中正确运行。

如果删除drawFirstObject,则第二个对象将具有texture1

如果删除drawSecondObject,则第一个对象将具有texture0

如果在drawFirstObjectdrawSecondObject之间,我会更改程序一段时间:

glUseProgram(0); // can be also any valid program other than the program from the next call
glUseProgram(program);

则两个对象都将具有CCD_ 10。

sampler2D不同的制服的值总是正确设置的。

我知道我可以只使用一个纹理图像单元绘制两个具有不同纹理的对象,并在绘制对象之前将适当的纹理绑定到该纹理图像单元,但我也想知道这里发生了什么。

我的代码有问题吗?在OpenGL ES 2.0中,是否可以像我在代码中所示的那样,仅通过在纹理图像单元之间切换来绘制具有不同纹理的对象?如果这是不可能的,OpenGL 2.0(在可能的情况下)和OpenGL ES 2.0之间的差异有记录吗?我找不到。

经过数小时的进一步研究,我发现这个问题是我的三星Galaxy Ace(GT-S5830)中使用的Adreno 200 GPU特有的。Adreno 200驱动程序似乎在对绘图函数的第一次调用中将纹理分配给采样器,然后忽略采样器值(glUniform1i(samplerLocation, textureImageUnit))的任何更改,直到出现以下两种情况之一:

  • CCD_ 13是用不同的着色器程序调用的
  • 不同的纹理被绑定到着色器程序所使用的任何纹理图像单元

Adreno 200 GPU制造商的论坛上有一个帖子描述了同样的问题。

因此,如果使用相同的着色器程序和以前绑定的不同纹理多次调用绘图函数,则有两种解决方法可以解决所描述的问题:

  1. 在每个绘图函数之前调用glUseProgram(0); glUseProgram(yourDrawingProgram);

  2. 在每次绘图调用之前,请将不同的纹理绑定到着色器程序使用的至少一个纹理图像单元。此解决方案可能很难维护,因为如果绑定已绑定到纹理图像单元的同一纹理,问题仍然存在。因此,在这种情况下,最简单的解决方案是在每次绘图调用之前,不更改采样器值并绑定着色器程序使用的所有纹理图像单元的纹理。

相关内容

最新更新