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.
source to share
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 ..
source to share