3

我正在尝试使用 OpenGL ES 2.0 for Android 中的一个着色器程序使用两种不同的纹理绘制两个对象。第一个对象应该有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

在带有 Android 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);

那么两个对象都会有texture1.

与 不同的制服的值sampler2D始终设置正确。

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

我的代码有问题吗?是否可以在 OpenGL ES 2.0 中仅通过在代码中显示的纹理图像单元之间切换来绘制具有不同纹理的对象?如果不可能,OpenGL 2.0(在可能的情况下)和 OpenGL ES 2.0 之间的区别是否记录在任何地方?我找不到它。

4

1 回答 1

3

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

  • glUseProgram用不同的着色器程序调用,
  • 不同的纹理绑定到着色器程序使用的任何纹理图像单元。

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

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

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

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

于 2012-12-03T19:23:41.397 回答