1
votes

I want to display an image as texture on a quad with OpenGL ES 2.0 using the Android NDK.

I have the following simple vertex and fragment shader:

#define DISP_SHADER_V_SRC "\
attribute vec4 aPos;\
attribute vec2 aTexCoord;\
varying vec2 vTexCoord;\
void main() {\
    gl_Position = aPos;\
    vTexCoord = aTexCoord;\
 }"

#define DISP_SHADER_F_SRC "\
precision mediump float;\n\
varying vec2 vTexCoord;\n\
uniform sampler2D sTexture;\n\
void main() {\n\
    gl_FragColor = texture2D(sTexture, vTexCoord);\n\
}"

At first, a native "create" method is called when the GLSurfaceView is created. It sets the clear color, builds the shader and gets me a texture id using glGenTextures. A "resize" method sets the current view size. Another method sets the texture data like this:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);

I don't believe that there's something wrong there. The important thing should be the "draw" method. After glClear, glViewport and glUseProgram I do the following:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texId);

glEnableVertexAttribArray(shAPos);
glVertexAttribPointer(shAPos, 3, GL_FLOAT, false, 0, quadVertices);

glVertexAttribPointer(shATexCoord, 2, GL_FLOAT, false, 0, quadTexCoordsStd);
glEnableVertexAttribArray(shATexCoord);

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// now glDisableVertex...

I can confirm that the shader basically works, since gl_FragColor=vec4(1.0); results in a white screen. It just does not work when I load a texture. I tried out setting the pixel data to "all white" using memset just to confirm that the issue is not related with my image data, but still the screen stays black. What am I missing?

1
Since you're able to draw with a modified shader, it sounds like the sampler is just finding zeroes in the texture image. Can you confirm that you're calling glBindTexture(GL_TEXTURE_2D, texId) before the glTexImage2D call? Is the texture using power-of-two sizes?fadden
I can confirm that. I'm calling glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texId);, then I set GL_CLAMP_TO_EDGE and generate mipmaps. I also checked that vTexCoord has valid values by setting gl_FragColor = vec4(vTexCoord.s, vTexCoord.t, 1.0, 1.0). It all does what it should, besides drawing the damn texture :(IsaacKleiner
Wow, this took some time... Well I'm not completely sure what the problem was, but I solved it like this: I noticed that drawing the texture worked when I called the texture loading function via JNI directly inside onSurfaceCreated. However, I wanted that the texture changes when I touch the view. I guessed it had something to do with the calling thread. So I moved the code to call the texture loading function from an OnClickListener directly to the class that implements the GLSurfaceView.Renderer. Now it works. Tricky thing though, since no errors were thrown :(IsaacKleiner
Sounds like you moved it to a different thread (UI thread vs. GLSurfaceView render thread). Do you have the same EGL context current in both threads simultaneously?fadden
I do not see any lines of code where you set the value of the uniform: sTexture to 0.Andon M. Coleman

1 Answers

1
votes

IsaacKleiner's own comment was correct, I have met with the same problem, I develop a android app with OpenGL ES 2.0 in C++, using NDK. The function to load texture was in the C++ part originally. For some reason, that did not work. Only after I move the load texture code to java part , did it work as normal. I load the texture in the java part, bind it as normal, and I pass the texture ID to the C++ JNI code. I do not know why there is such a problem. I can provide with a link, in which there is an example that use OpenGL ES 1.0 and NDK to show a cube. Although it is in Chinese, the code can explain itself. please pay attention to how the texture is generated and how the texture id is passed between Java and C++.