Adam Phelps
Adam Phelps

Reputation: 479

Unable to get texture to render to quad in OpenGL ES 2.0 running on Android

When I launch the project I get an ominously black quad rendered inside an expectedly cyan background. I have determined that the texture coordinates are being interpolated properly with the commented out line of code in the fragment shader. I have tried a number of different ways of loading a texture and have always got the same result. The temporary bit of code that loads the 4 pixel texture is copied verbatim out of an example from a book. However I have included this as well just in case I have made an oversight.

I have attempted to remove impertinent code. But, I'm still quite new to this and continually learning the full meaning of much of the code. Additionally, much of the code has been adapted from different sources. So, I apologize for the messiness, inconsistent variable naming, and verbosity. I do feel like the issue is in the first several lines. Thanks in advance for all insight. Even any information on how I could go about debugging this would be appreciated; I feel quite in the dark when issues come up when working on this project.

Draw Frame:

public void onDrawFrame(GL10 gl) 
{

    GLES20.glClearColor(0.0f, 1.0f, 1.0f, 1.0f);

    GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);                    
    update();

    GLES20.glUseProgram(mProgramHandle);
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureHandle);
    GLES20.glUniform1i(mTextureUniformHandle, 0);

    //For some reason I think the problem is in this area

    Matrix.setIdentityM(mModelMatrix, 0);

    quadVerts.position(mPositionOffset);
    GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false, mStrideBytes, quadVerts);        
    GLES20.glEnableVertexAttribArray(mPositionHandle);

    quadVerts.position(mColorOffset);
    GLES20.glVertexAttribPointer(mColorHandle, mColorDataSize, GLES20.GL_FLOAT, false, mStrideBytes, quadVerts);        
    GLES20.glEnableVertexAttribArray(mColorHandle);

    GLES20.glVertexAttribPointer(mTextureCoordinateHandle, 2, GLES20.GL_FLOAT, false, 0, quadTex);        
    GLES20.glEnableVertexAttribArray(2);


    Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);

    Matrix.multiplyMM(mMVPMatrix, 0, mOrthographicMatrix, 0, mMVPMatrix, 0);

    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);         

    //...    
    checkGlError("on draw frame: ");
}

Surface Changed:

        public void onSurfaceChanged(GL10 glUnused, int width, int height) 
{
    GLES20.glViewport(0, 0, width, height);
    w = width;
    h = height;
    final float near = 1.0f;
    final float far = 10.0f;
    Matrix.orthoM(mOrthographicMatrix, 0, 0, width, 0, height, near, far);
    float[] pVertsData =
        {
            20.0f, 20.0f, 0.0f, 
            1.0f, 1.0f, 1.0f, 1.0f,

            (float) width- 20.0f, 20.0f, 0.0f, 
            1.0f, 1.0f, 1.0f, 1.0f,

            (float) width - 20.0f, (float) height - 20.0f, 0.0f, 
            1.0f, 1.0f, 1.0f, 1.0f,

            20.0f, (float) height - 20.0f, 0.0f,
            1.0f, 1.0f, 1.0f, 1.0f
        };

    quadVerts = ByteBuffer.allocateDirect(pVertsData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();

    quadVerts.put(pVertsData).position(0);

    float texture[] = 
        {
            0.0f, 0.0f,
            1.0f, 0.0f,
            1.0f, 1.0f,
            0.0f, 1.0f
        };
    quadTex = ByteBuffer.allocateDirect(texture.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
    quadTex.put(texture).position(0);

checkGlError("surface changed: ");
}

Surface Created:

public void onSurfaceCreated(GL10 glUnused, EGLConfig config) 
{
    mParticleSystem = new ParticleSystem();
     //GLES20.glEnable(GLES20.GL_TEXTURE_2D);
     if (mTextureHandle != 1)
    mTextureHandle = loadGLTexture(activeContext, resourceID);
    GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    final float eyeX = 0.0f;
    final float eyeY = 0.0f;
    final float eyeZ = 1.5f;

    final float lookX = 0.0f;
    final float lookY = 0.0f;
    final float lookZ = -5.0f;

    final float upX = 0.0f;
    final float upY = 1.0f;
    final float upZ = 0.0f;

    Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);

    final String vertexShader = 
            "uniform mat4 u_MVPMatrix;              \n"

        +   "attribute vec4 a_Position;             \n"
        +   "attribute vec4 a_Color;                \n"
        +   "attribute vec2 a_TexCoordinate;        \n"

        +   "//varying vec3 v_Position;             \n"
        +   "varying vec4 v_Color;                  \n"
        +   "varying vec2 v_TexCoordinate;          \n"

        +   "void main()                            \n"
        +   "{                                      \n"
        +   "   v_TexCoordinate = a_TexCoordinate;  \n"
        +   "   v_Color = a_Color;                  \n"
        +   "   gl_Position = u_MVPMatrix           \n"
        +   "               * a_Position;           \n"
        +   "}                                      \n";

    final String fragmentShader =
            "precision mediump float;       \n"

        +   "uniform sampler2D u_Texture;   \n" 
        +   "varying vec4 v_Color;          \n"
        +   "varying vec2 v_TexCoordinate;  \n"
        +   "void main()                    \n"
        +   "{                              \n" 
        +   "   vec4 baseColor;"
        +   "   baseColor = texture2D(u_Texture, v_TexCoordinate);      \n"
        +   "    " 
        +   "   gl_FragColor = baseColor;   \n" 
        +   "                           \n"
        +   "   //gl_FragColor = vec4(v_TexCoordinate.x, v_TexCoordinate.y, 0.0, 1.0);  \n"
        +   "   //gl_FragColor = v_Color;       \n"

        +   "}                              \n";

    //... Compile Shaders


    int programHandle = GLES20.glCreateProgram();
    if (programHandle != 0) 
    {
        GLES20.glAttachShader(programHandle, vertexShaderHandle);           
        GLES20.glAttachShader(programHandle, fragmentShaderHandle);
        GLES20.glBindAttribLocation(programHandle, 0, "a_Position");
        GLES20.glBindAttribLocation(programHandle, 1, "a_Color");
        GLES20.glBindAttribLocation(programHandle, 2, "a_TexCoordinate");
        GLES20.glLinkProgram(programHandle);
        final int[] linkStatus = new int[1];
        GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);
        if (linkStatus[0] == 0) 
        {               
            GLES20.glDeleteProgram(programHandle);
            programHandle = 0;
        }
    }

    if (programHandle == 0)
    {
        throw new RuntimeException("Error creating program.");
    }
    mMVPMatrixHandle = GLES20.glGetUniformLocation(programHandle, "u_MVPMatrix");        
    mPositionHandle = GLES20.glGetAttribLocation(programHandle, "a_Position");
    mColorHandle = GLES20.glGetAttribLocation(programHandle, "a_Color");
    mTextureUniformHandle = GLES20.glGetUniformLocation(programHandle, "u_Texture");
    mTextureCoordinateHandle = GLES20.glGetAttribLocation(programHandle, "a_TexCoordinate");

    //GLES20.glUseProgram(programHandle);  
    mProgramHandle = programHandle;
checkGlError("surface created: ");
    }

Load Texture:

private int loadGLTexture(Context context, final int resourceId)
{


    final int[] textureHandle = new int[1];
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1);
        GLES20.glGenTextures(1, textureHandle, 0);

        byte[] pixels = 
            {  
                (byte) 0xff,   0,   0, 
                0, (byte) 0xff,   0, 
                0,   0, (byte) 0xff,
                (byte) 0xff, (byte) 0xff,   0
            };

        ByteBuffer pixelBuffer = ByteBuffer.allocateDirect(4*3);
        pixelBuffer.put(pixels).position(0);
        GLES20.glBindTexture ( GLES20.GL_TEXTURE_2D, textureHandle[0] );
        GLES20.glTexImage2D ( GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, 2, 2, 0, GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, pixelBuffer );
        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 );
        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);


    }
    if (textureHandle[0] == 0)
    {
        throw new RuntimeException("Error loading texture.");
    }
    checkGlError("create texture: ");
    return textureHandle[0];
}

Code updated as suggested below.

Upvotes: 2

Views: 1233

Answers (2)

Adam Phelps
Adam Phelps

Reputation: 479

Finally, located the problem. I removed a lot of commented out lines in the posted code for simplicity's sake. One of which was the line in the fragment shader directly before "gl_FragColor = baseColor;". However this line did not have '\n'... So in effect I had commented out the line that was supposed to actually put the texture on the quad. So the code above will actually run properly while the code that was in my project would not.

Upvotes: 2

Tim
Tim

Reputation: 35933

Couple thoughts. I don't know if your problem is in here, but here goes:

  1. You're not doing any error checking with glGetError (you should do this). It will help you find so many problems.

  2. GLES20.glEnable(GLES20.GL_TEXTURE_2D); is not a legal call in GLES2.0. Enabling GL_TEXTURE_2D only effects the deprecated fixed function pipeline. This is likely generating an error, but shouldn't cause your problem.

Can you try adding error checking, and report back if there are any problems? I scanned your code a bit but it looks pretty correct so far.

Upvotes: 1

Related Questions