Search code examples
javaandroidtexturesopengl-es-2.0

Android: texture shows up as solid color


I'm attempting to get a texture to show up on on a square made from a triangle fan, the texture is made from a Canvas. The main color is just yellow and a smaller box is drawn inside of it, but the final texture is just solid yellow.

Yellow square with no texture (picture)

enter image description here

Fragment shadder:

public static final String fragmentShaderCode_TEXTURED =
                "precision mediump float;" +
                "varying vec2 v_texCoord;" +
                "uniform sampler2D s_texture;" +
                "void main() {" +
                //"gl_FragColor = vColor;"+
                "  gl_FragColor = texture2D( s_texture, v_texCoord );" +
                "}";

Texture generation:

public static int loadGLTexture(String s){
    Rect r = new Rect();
    ThreadDat.get().paint.getTextBounds(s, 0, 1, r); //get string dimensions, yeilds 8x9 pxls
    Bitmap bitmap = Bitmap.createBitmap(bestSize(r.width()),bestSize(r.height()), Bitmap.Config.ARGB_8888);
    //example size is 16x16pxls
    Log.i("TextureSize", r.width() + " " + r.height());
    Canvas c = new Canvas(bitmap);

    //some temporary test code setting the background yellow
    //Paint colors are stored per thread, only one right now
    ThreadDat.get().paint.setARGB(255, 255, 255, 0);
    c.drawRect(0, 0, c.getWidth(), c.getHeight(), ThreadDat.get().paint);
    //type the letter, in this case "A" in blue
    ThreadDat.get().paint.setARGB(255, 0, 0, 255);
    ThreadDat.get().paint.setTypeface(Typeface.create("Consolas", Typeface.NORMAL));
    c.drawText(s.charAt(0) + "", 0, 0, ThreadDat.get().paint);
    //draw another square that is half width and height, should be Blue
    c.drawRect(0, 0, c.getWidth() / 2, c.getHeight() / 2, ThreadDat.get().paint);
    return loadTexture(bitmap);
}

Draw code:

@Override
public void draw() {
    //clearing any error to check if program has an error
    GLES20.glGetError();
    //get the compiled shader for textured shapes
    int prgm = MyGLRenderer.getSTRD_TXTR_SHDR();
    GLES20.glUseProgram(prgm);
    //check for new errors and log to logcat (nothing)
    MyGLRenderer.logError();

    //setup projection view matrix
    float[] scratch = new float[16];
    Matrix.setIdentityM(scratch, 0);
    Matrix.multiplyMM(scratch, 0, MyGLRenderer.getmMVPMatrix(), 0, scratch, 0);
    //apply translations to matrix
    Matrix.translateM(scratch, 0, xOffset, yOffset, zOffset);
    Matrix.setRotateEulerM(scratch, 0, yaw, pitch, roll);


    //get vPosition variable handle from chosen shader
    mPosHandle = GLES20.glGetAttribLocation(prgm, "vPosition");
    GLES20.glEnableVertexAttribArray(mPosHandle);

    GLES20.glVertexAttribPointer(mPosHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT,
            false, VERTEX_STRIDE, vertexBuffer);

    ////pass color data (set to white)
    //mColorHandle = GLES20.glGetUniformLocation(prgm, "vColor");
    //GLES20.glUniform4fv(mColorHandle, 1, color, 0);


    //use texture0
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    //use texture from -> int textureID = MyGLRenderer.loadGLTexture("A");
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureID);
    //get handel for "uniform sampler2D s_texture;" to set value
    int txtureHandle = GLES20.glGetUniformLocation(prgm, "s_texture");
    GLES20.glUniform1i(txtureHandle, 0); //set s_texture to use binded texture 0


    //pass in texture coords (u,v / s,t)
    int textureCoordHndl = GLES20.glGetAttribLocation(prgm, "a_texCoord");
    GLES20.glVertexAttribPointer(textureCoordHndl, 2/*size, 2 points per vector*/,
            GLES20.GL_FLOAT, false, 0, textureBuffer);

    //pass in  the model view projection matrix
    mMVPMatrixHandle = GLES20.glGetUniformLocation(prgm, "uMVPMatrix");
    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, scratch, 0);



    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertex_count);

    GLES20.glDisableVertexAttribArray(mPosHandle);
    MyGLRenderer.logError();
}

I tried using the same coordinate set as used in this example:

Vertices for square:

{           0, 0, 0,  //bottom left
            0, height, 0,  //topLeft
            width, 0, 0,  // bottom Right
            width, height, 0)}; //topRight

Texture coords:

        0.0f, 1.0f,     // top left     (V2)
        0.0f, 0.0f,     // bottom left  (V1)
        1.0f, 1.0f,     // top right    (V4)
        1.0f, 0.0f      // bottom right (V3)

Similar Issue


Solution

  • This does sound like there is an issue with texture coordinates. Since the whole thing is yellow I would suspect that the v_texCoord is always (0,0) in your fragment shader so the first texture pixel is being repeated.

    The texture itself seems to be ok since the color is being drawn. Without the texture you would most likely see a black rectangle.

    Anyway to handle such issues you need to be a bit inventive in debugging, testing. For testing the coordinates use gl_FragColor = vec4( v_texCoord.x, v_texCoord.y, .0, 1.0 );. This should output a gradient rectangle where top left is black, top right is red, bottom left is green. If you do not see this result then your texture coordinates are incorrect. In this case first check if the varying is correctly connected from the vertex shader. You may use v_texCoord = vec2(1.0, 0.0) in the vertex shader and the result should be a red rectangle (assuming you still have the previous test in the fragment shader). If the rectangle is red then the issue is most likely in your handles and not in the shaders (otherwise the varying is incorrectly set. Maybe a mismatch in naming). Check what is the value of the handle textureCoordHndl. If this is a negative value then the handle was not connected. This is most likely due to a mismatch in the naming.

    From further inspection:

    You are missing the enabling of the attribute for texture coordinates GLES20.glEnableVertexAttribArray(textureCoordHndl);. Remember that each of the attributes must be enabled before you use them.