Android OpenGL ES 2.0 black texture

In the foreword to this: Yes, I looked at a lot of "Android OpenGL ES 2.0 Android Textures" defined earlier on this site. No, none of them helped me. No, I'm not sure if I can better formulate the title in the appropriate number of characters.

I followed several tutorials and was able to create a very simple render class that loaded and displayed textures correctly (project A). Then I tried to implement this very simple rendering system in the game engine (project B). Everything works exactly the same, except texture2D () returns black for some reason. I've tried a lot of debugging and a lot of googling all to no avail. And so I ask for help.

My vertex and fragment shaders. They worked great in project A so I don't think this is the source of the problem, just for the sake of completeness.

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);" +
"}";

      

I build, compile and attach these shaders to the program without error. After that I set my handles accordingly - I also set u_Texture to point to texture unit 0, because that doesn't change:

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

      

Then I load my texture:

...
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};
}

      

I didn't need to set texture wrapping in project A, although my texture is 32 x 19. I changed my texture to 32 x 32 and set texture snapping to clamps as a precaution so no one would try to say it was my mistake. The bitmap is loading - I wrote the width, height and a few selected pixels for debugging and they were in place.

In my draw method, I include the a_TexCoord attribute and point it to the data:

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

      

I wrote the whole mTexCoordBuffer from a debug message and loaded the texture coordinate data correctly.

Finally, I set the active texture block to 0, bind texture data to it and draw:

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

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

      

I'm very new to the whole graphics library, but I've done my best to get along with what's going on here. I thought I understood all this, but this is clearly not the case. From what I can tell, the shaders are working correctly - the black rectangle appears exactly where it should (and did in project A). The texture coordinate data I am passing in is exactly the same as in project A and I have not changed anything with how this is loaded. This leaves the actual texture data as a prime suspect, however I tried to set it up the same way as in Project A and it seems to be correct. I would really appreciate it if someone more experienced than I could point out my mistake.

+3


source to share


1 answer


Alas, I knew it would be something worthy of a face. Though I suppose I should be happy that I found the error as soon as I did, and that I actually understood the GLES code I was using. On the other hand, I don't seem to understand the basics of java.

Anyway, it turns out that I was doing a whole bunch of things in the constructors of my Renderer and GameState classes that I shouldn't have done at this point. I made an allocateGameState () method in GameState and called it in onSurfaceCreated () of my Renderer; problem solved.



The part I'm still confused about is this: I figured out that it was my mistake by going back to project A and changing the code until it emulates project B. At the very end I got lucky and made the same mistake of misusing the Renderer constructor to create texture / shader / program data. This time, however, I was penalized with the following error: "Calling the OpenGl ES API without the current context". I quickly fixed this and applied the same fix to project B, but it makes me wonder why I was not getting the same error in project B ..

+4


source







All Articles