简体   繁体   中英

Android OpenGL ES 2.0 black texture

To preface this: Yes, I have looked at the large amount of "Android OpenGL ES 2.0 black textures" questions asked previously on this site. No, none of them were helpful to my situation. No, I'm not sure if I can phrase the title any better in an appropriate amount of characters.

I followed a number of tutorials and was able to set up a very simple renderer class that properly loaded and rendered textures (project A). I then tried implementing this very simple rendering system in a game engine (project B). Everything works the exact same, except texture2D() returns black for some reason. I have tried much debugging and much googling all to no avail. And so I ask for assistance.

My vertex and fragment shaders. They worked just fine in project A, so I don't think this is the source of the problem, just including 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 create, compile, and attach these shaders to the program without error. After this, I set my handles accordingly - I also set u_Texture to point to texture unit 0 because this does not 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);
...

I then 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 did not need to set texture wrapping in project A even though my texture is 32 x 19. I changed my texture to 32 x 32 and set texture wrapping to clamp just as a precautionary measure and so no one would try to tell me that was my error. The bitmap is loading - I wrote width, height, and a few select pixels to debug and they were spot on.

In my draw method, I enable 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 out to a debug message and it's correctly loaded with the texture coordinate data.

Finally, I set the active texture unit to 0, bind my 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 thing, but I've done my best to come to terms with what's actually going on here. I thought I understood it all, however that's obviously not the case. From what I can tell, the shaders are working properly - the black rectangle appears exactly where it should (and did in project A). The texture coordinate data that I'm passing in is the exact same as in project A and I changed nothing with how that is loaded. This leaves the actual texture data as the primary suspect, however I tried to set it up just like I did in project A and it seems correct. I would very much appreciate if someone more experienced than I could point out my mistake.

Alas, I knew it would be something worthy of a facedesk. Though I suppose I should be happy that I found the error as soon as I did and that I did, in fact, understand the GLES code I was using. On the other hand, I apparently do not understand the basics of java.

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

The part that I'm still confused about is: I found out that this was my error by going back to project A and altering code until it emulated project B. At the very end, I got lucky and made the same mistake of misusing the Renderer's constructor to instantiate texture/shader/program data. This time, however, I was barraged with the following error: "call to OpenGl ES API with no current context". I quickly fixed this and applied the same fix to project B, but it makes me wonder why I wasn't getting the same error in project B..

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM