Search code examples
androidopengl-esopengl-es-2.0textures

OpenGL ES 2.0 texture showing up black


I've seen a few questions like this on SO, but nothing which has helped me so far. I've made GLTriangle, and GLRectangle classes. I can draw these two shapes no problem, with colors. I'm trying to implement textures into them, and I'm having trouble getting it to work (and debugging).

I'll try to post the relevant code of what I have so far, if you need to see more, let me know.

EDIT: Ok, so after fixing the mistake with the texcoord handlers, I'm still getting a black square. The only time glGetError reports anything is after calling GLES20.glEnable(GLES20.GL_TEXTURE_2D);

GLRectangle relevant code:

@Override
public void onSurfaceCreated() {
    ByteBuffer vertexByteBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
    vertexByteBuffer.order(ByteOrder.nativeOrder());
    vertexBuffer = vertexByteBuffer.asFloatBuffer();
    vertexBuffer.put(vertices);
    vertexBuffer.position(0);

    vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
    fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);

    mProgram = createAndLinkProgram(VertexShaderHandle(), FragmentShaderHandle(), new String[] { "uMVPMatrix", "vPosition", "a_TexCoordinate" });
    muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
    maPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
    loadTexture(context, imageId);
    ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
ibb.order(ByteOrder.nativeOrder());
indexBuffer = ibb.asShortBuffer();
indexBuffer.put(indices);
indexBuffer.position(0);

ByteBuffer tbb = ByteBuffer.allocateDirect(texCoords.length * 4);
tbb.order(ByteOrder.nativeOrder());
textureCoordBuffer = tbb.asFloatBuffer();
textureCoordBuffer.put(texCoords).position(0);
}

And in onDrawFrame:

GLES20.glUseProgram(mProgram);
GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, 12, vertexBuffer);
GLES20.glEnableVertexAttribArray(maPositionHandle);
Matrix.multiplyMM(mMVPMatrix, 0, projMatrix, 0, mvMatrix, 0);
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
mTextureUniformHandle = GLES20.glGetUniformLocation(mProgram, "u_Texture");
        mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgram, "a_TexCoordinate");

GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle);
GLES20.glUniform1i(mTextureUniformHandle, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length, GLES20.GL_UNSIGNED_SHORT, indexBuffer);

I know, or at least I'm fairly certain that the bitmap is being loaded, as I get the int handle returned when loading it (it will cause a runtime error if the int is 0).

I'm guessing it has something to do with the texture coordinates.

Here's what I have for my tex coords:

texCoords = new float[] { 
    0, 0,
    0, 1,
    1, 1,
    1, 0
};  

Just in case it IS something with the texture loader, here it is:

int[] textureHandle  = new int[1];

            GLES20.glGenTextures(1, textureHandle, 0);

            if (textureHandle[0] != 0) {
                final BitmapFactory.Options options = new BitmapFactory.Options();
                options.inScaled = false;

                final Bitmap bitmap = BitmapFactory.decodeResource(view.getContext().getResources(), resourceId, options);



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

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


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


                bitmap.recycle();

            }

            if (textureHandle[0] == 0) {
                throw new RuntimeException("Unable to load texture!");
            }
            mTextureDataHandle = textureHandle[0];

EDIT: Forgot to add my shaders, I'm just setting the string through code right now:

setVertexShader( 
                "uniform mat4 uMVPMatrix;   \n" +
                "uniform mat4 MVMatrix;     \n" +
                "attribute vec4 vPosition;  \n" +
                "attribute vec2 a_TexCoordinate;    \n" +                   
                "varying vec2 v_TexCoordinate;  \n" +

                "void main() {      \n" +

                "v_TexCoordinate = a_TexCoordinate; \n" +
                "gl_Position = uMVPMatrix * vPosition;  \n" +
                "}  \n");                   

        setFragmentShader("precision mediump float;  \n" +
                "uniform sampler2D u_Texture;   \n" +                   
                "varying vec2 v_TexCoordinate;  \n" +
                "void main() {              \n" +
                "gl_FragColor = texture2D(u_Texture, v_TexCoordinate); \n" +
                "}                         \n");

Solution

  • mTextureCoordinateHandle = GLES20.glGetUniformLocation(mProgram, "u_Texture");
    mTextureUniformHandle = GLES20.glGetAttribLocation(mProgram, "a_TexCoordinate");
    
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle);
    

    This is all backward. You're getting the texcoord location and setting it as the uniform, and getting the uniform location and setting it as the texcoord. Plus you're not even doing anything with the texcoord attribute.