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.

| improve this question | | | | |
  • \$\begingroup\$ Shouldn't you be using GL_LINEAR_MIPMAP_LINEAR for your min filter if you want to generate mipmaps? \$\endgroup\$ – Maximus Minimus Nov 8 '12 at 18:18

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.

| improve this answer | | | | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.