Why do my 512x512 bitmaps look jaggy on Android OpenGL?

Posted by Milo Mordaunt on Game Development See other posts from Game Development or by Milo Mordaunt
Published on 2012-11-08T17:17:29Z Indexed on 2012/11/08 17:26 UTC
Read the original article Hit count: 365

Filed under:
|
|

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
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

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

GLES20.glUseProgram(mProgram);

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.glEnableVertexAttribArray(posAttr);
GLES20.glEnableVertexAttribArray(texAttr);

GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
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.glDisableVertexAttribArray(posAttr);
GLES20.glDisableVertexAttribArray(texAttr);

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);
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
GLES20.glDepthMask(false);

GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);

GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glEnable(GLES20.GL_DITHER);
}

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) {
        "discard;
    }
}

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.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, temp, 0);
GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
temp.recycle();

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.

© Game Development or respective owner

Related posts about android

Related posts about textures