Android OpenGL ES 2.0黑色纹理

时间:2014-09-13 20:37:51

标签: android opengl-es textures opengl-es-2.0

前言:是的,我已经看过大量的" Android OpenGL ES 2.0黑色纹理"先前在本网站上提出的问题。不,他们都没有对我的情况有所帮助。不,我不确定我是否可以用适当数量的字符来更好地标题。

我遵循了一些教程,并且能够设置一个非常简单的渲染器类,正确加载和渲染纹理(项目A)。然后我尝试在游戏引擎(项目B)中实现这个非常简单的渲染系统。一切都是完全相同的,除了texture2D()由于某种原因返回黑色。我已经尝试了很多调试和谷歌搜索都无济于事。所以我请求帮助。

我的顶点和片段着色器。他们在项目A中工作得很好,所以我不认为这是问题的根源,只是为了完整起见。

private static final String VERTEX_SHADER_SOURCE =
...
"attribute vec2 a_TexCoord;" +
"varying vec2 v_TexCoord;" +

"void main() {" +
"   v_TexCoord = a_TexCoord;" +
...
"}";


private static final String FRAGMENT_SHADER_SOURCE =
"precision mediump float;" +
"uniform sampler2D u_Texture;" +
"varying vec2 v_TexCoord;" +

"void main() {" +
"   gl_FragColor = texture2D(u_Texture, v_TexCoord);" +
"}";

我创建,编译并将这些着色器附加到程序中而没有错误。在此之后,我相应地设置了句柄 - 我还将u_Texture设置为指向纹理单元0,因为这不会改变:

...
sTexUniformHandle = GLES20.glGetUniformLocation(sProgramHandle, "u_Texture");
sMVPHandle = GLES20.glGetUniformLocation(sProgramHandle, "u_MVPMatrix");
sPositionHandle = GLES20.glGetAttribLocation(sProgramHandle, "a_Position");
sTexCoordHandle = GLES20.glGetAttribLocation(sProgramHandle, "a_TexCoord");

GLES20.glUseProgram(sProgramHandle);
GLES20.glUniform1i(sTexUniformHandle, 0);
GLES20.glUseProgram(0);
...

然后我加载纹理:

...
int[] texData = Utils.createTexture(context, resId);
mTexDataHandle = texData[0];
...
public static int[] createTexture(Context context, int resId) { // returns {textureHandle, width, height}
    int width = -1;
    int height = -1;

    int[] texHandle = new int[1];
    GLES20.glGenTextures(1, texHandle, 0);

    if (texHandle[0] != 0) {
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inScaled = false;

        final Bitmap bm = BitmapFactory.decodeResource(context.getResources(), resId, opts);
        width = bm.getWidth();
        height = bm.getHeight();

        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texHandle[0]);

        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);

        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bm, 0);

        bm.recycle();
    }

    if (texHandle[0] == 0) {
        throw new RuntimeException("texture load error");
    }

    return new int[]{texHandle[0], width, height};
}

即使我的纹理是32 x 19,我也不需要在项目A中设置纹理包装。我将纹理更改为32 x 32并将纹理包装设置为钳位,这是一种预防措施,因此没有人会试图告诉我是我的错误。位图正在加载 - 我写了宽度,高度和几个选择像素进行调试,它们都是现货。

在我的draw方法中,我启用a_TexCoord属性并将其指向数据:

...
GLES20.glEnableVertexAttribArray(sTexCoordHandle);
...
GLES20.glVertexAttribPointer(sTexCoordHandle, mTexCoordDataSize, GLES20.GL_FLOAT, false, 0, mTexCoordBuffer);
...

我将整个mTexCoordBuffer写入调试消息,并且正确加载了纹理坐标数据。

最后,我将活动纹理单元设置为0,将纹理数据绑定到它,然后绘制:

...
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexDataHandle);

GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
...

我对整个图形库的事情都很陌生,但我已经尽力与这里的实际情况达成协议。我以为我理解了这一切,但事实并非如此。据我所知,着色器工作正常 - 黑色矩形正好出现在它应该的位置(在项目A中也是如此)。我传入的纹理坐标数据与项目A完全相同,我没有改变加载的方式。这使得实际的纹理数据成为主要的嫌疑人,但是我试图像在项目A中那样设置它并且看起来是正确的。如果比我更有经验的人能指出我的错误,我将非常感激。

1 个答案:

答案 0 :(得分:4)

唉,我知道这将是一个值得面子的东西。虽然我想我应该感到高兴,因为我发现了错误,而且事实上,我确实理解了我正在使用的GLES代码。另一方面,我显然不了解java的基础知识。

无论如何,事实证明我在Renderer和GameState类的构造函数中做了很多东西,我当时不应该这样做。我在GameState中创建了一个allocateGameState()方法,并在我的渲染器的onSurfaceCreated()中调用它;问题解决了。

我仍然感到困惑的部分是:我发现这是我的错误,回到项目A并更改代码,直到它模拟项目B.最后,我很幸运并且做了错误使用Renderer的构造函数来实例化纹理/着色器/程序数据。但是,这一次,我被以下错误搞砸了:"在没有当前上下文的情况下调用OpenGl ES API"。我很快修复了这个并对项目B应用了相同的修复,但它让我想知道为什么我在项目B中没有得到相同的错误..