This is sort of driving me nuts, I've googled and googled and tried everything I can think of, but my sprites still look super blurry and super jaggy. Example:

Here: https://docs.google.com/open?id=0Bx9Gbwnv9Hd2TmpiZkFycUNmRTA

If you click through to the actual full size image you should see what I mean, it's like it's taking and average of every 5*5 pixels or something, the background looks really blurry and blocky, but the ball is the worst. The clouds look all right for some reason, probably because they're mostly transparent.

I know the pngs aren't top notch themselves but hey, I'm no artist!

I would imagine it's a problem with either:

a. How the pngs are made

example sprite (512x512): https://docs.google.com/open?id=0Bx9Gbwnv9Hd2a2RRQlJiQTFJUEE

b. How my Matrices work

This is the relevant parts of the renderer:

public void onDrawFrame(GL10 unused) {
if(world != null) {
    dt = System.currentTimeMillis() - endTime;

    world.update( (float) dt);

    // Redraw background color

    Matrix.setIdentityM(mvMatrix, 0);
    Matrix.translateM(mvMatrix, 0, 0f, 0f, 0f);

    world.draw(mvMatrix, mProjMatrix);

        endTime = System.currentTimeMillis();
} else {
    Log.d(TAG, "There is no world....");

public void onSurfaceChanged(GL10 unused, int width, int height) {
    GLES20.glViewport(0, 0, width, height);

Matrix.orthoM(mProjMatrix, 0, 0, width /2, 0, height /2, -1.f, 1.f);

And this is what each Quad does when draw is called:

public void draw(float[] mvMatrix, float[] pMatrix) {
Matrix.setIdentityM(mMatrix, 0);
Matrix.setIdentityM(mvMatrix, 0);

Matrix.translateM(mMatrix, 0, xPos, yPos, 0.f);
Matrix.multiplyMM(mvMatrix, 0, mvMatrix, 0, mMatrix, 0);
Matrix.scaleM(mvMatrix, 0, scale, scale, 0f);
Matrix.rotateM(mvMatrix, 0, angle, 0f, 0f, -1f);


posAttr = GLES20.glGetAttribLocation(mProgram, "vPosition");
texAttr = GLES20.glGetAttribLocation(mProgram, "aTexCo");
uSampler = GLES20.glGetUniformLocation(mProgram, "uSampler");
int alphaHandle = GLES20.glGetUniformLocation(mProgram, "alpha");

GLES20.glVertexAttribPointer(posAttr, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, vertexBuffer);
GLES20.glVertexAttribPointer(texAttr, 2, GLES20.GL_FLOAT, false, 0, texCoBuffer);


GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
GLES20.glUniform1i(uSampler, 0);
GLES20.glUniform1f(alphaHandle, alpha);

mMVMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVMatrix");
mPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uPMatrix");

GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mvMatrix, 0);
GLES20.glUniformMatrix4fv(mPMatrixHandle, 1, false, pMatrix, 0);

GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, 4, GLES20.GL_UNSIGNED_SHORT, indicesBuffer);


GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);

c. How my texture loading/blending/shaders setup works

Here is the renderer setup:

 public void onSurfaceCreated(GL10 unused, EGLConfig config) {
    // Set the background frame color
    GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);



Here is the vertex shader:

    attribute vec4 vPosition;
attribute vec2 aTexCo;
varying vec2 vTexCo;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;

void main() {
  gl_Position = uPMatrix * uMVMatrix * vPosition;
  vTexCo = aTexCo;

And here's the fragment shader:

    precision mediump float;
uniform sampler2D uSampler;
uniform vec4 vColor;
varying vec2 vTexCo;
varying float alpha;
void main() {
    vec4 color = texture2D(uSampler, vec2(vTexCo));

    gl_FragColor = color;
    if(gl_FragColor.a == 0.0) {

This is how textures are loaded:

    private int loadTexture(int rescource) {
int[] texture = new int[1];
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inScaled = false;

Bitmap temp = BitmapFactory.decodeResource(context.getResources(), rescource, opts);

GLES20.glGenTextures(1, texture, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, temp, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);

return texture[0];

I'm sure I'm doing about 20,000 things wrong, so I'm really sorry if the problem is blindingly obvious...

The test device is a Galaxy Note, running a JellyBean custom ROM, if that matters at all. So the screen resolution is 1280x800, which means... The background is 1024x1024, so yeah it might be a little blurry, but shouldn't be made of lego.

Thank you so much, any answer at all would be appreciated.

  • \$\begingroup\$ Shouldn't you be using GL_LINEAR_MIPMAP_LINEAR for your min filter if you want to generate mipmaps? \$\endgroup\$ Nov 8, 2012 at 18:18

1 Answer 1


You are taking a 512x512 image and smooshing it into an area approximately 120x120 pixels. Thus, you should expect that each pixel is about the average of a 5x5 block. You're using linear texture filtering so that would be expected.

It might be better to use unscaled images if you're going to reduce the resolution by such a large amount. You can control the quality easily since what you see is what you get. Aside from that it will load faster and run faster on phones. A 512x512 image requires an immense amount of memory bandwidth to draw compared to say 128x128 (16x as much, in fact) which is a performance killer on mobile GPUs.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .