Texture artifacting/bleeding Open GL ES 1.X

I’m using the old 1.1 system to render my tiles and am getting some grainy effects on the edges of certain tiles with a specific phone. (A phone with 450 Mhz GPU will render fine, the one in question is 300 Mhz) I’m wondering if there’s a setting I need to use or if it’s just that the mobile device can’t render fast enough, which I would then need to optimize.

Here’s what I use to bind the texture, (it’s a 320x320 texture atlas for a total of 100 tiles)


                       InputStream inputStream = assetM.open(stream);
		       Bitmap _textureMAP = BitmapFactory.decodeStream(inputStream);
			
			gl.glGenTextures(1, tex, 0);
			gl.glBindTexture(GL10.GL_TEXTURE_2D, tex[0]);
			
			gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
			gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_NEAREST);
			
			gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
			gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
			
			GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, _textureMAP, 0);
			
			_textureMAP.recycle();

And these are the settings I use for the GL Surface View (window)


                gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		
		gl.glEnable(GL10.GL_TEXTURE_2D);
		gl.glEnable(GL10.GL_BLEND);
		gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);


Each tile type has it’s own st (uv) coordinates and every tile has it’s own vertex buffer. There’s also a method in tile update to make sure the tile is inside my viewport and will only be rendered if it is. So for each frame to draw tiles it goes like this


gl.glBindTexture(GL10.GL_TEXTURE_2D, bitmaps.worldOneTextures.tex[0]);
gl.glLoadIdentity();

for (int i = 0; i < mScreen.tiles.size(); i++) {

	Tile t = mScreen.tiles.get(i);
	if (!t.drawIt) {  continue;  }
	drawTile(TileVBOs.get(i), texCoords.get(Integer.toString(t.type)), gl);
}

private void drawTile(FloatBuffer vbo, FloatBuffer coords, gl) {

	gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vbo);
	gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, coords.position(0));
		
	gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, vertices.length / 3);
	
}

the vertex buffers are in an ArrayList “TileVBOs” and the uv coordinates are in a HashMap<String, FloatBuffer> “texCoords”

I found this article helpful for setting up my texture coordinates but it still hasn’t solved my issue, so I’ll keep looking. If anyone has any ideas, I’m all ears.

I did stumble at that question about a month ago. Did implement it like this in my engine.


public Texture getCell(int row, int column)
{
    if (row >= cells[0].length)
        throw new ArithmeticException("Cannot get past the last row");

    if (column >= cells.length)
        throw new ArithmeticException("Cannot get past the last column");

    if (cells[column][row] == null)
    {
        float minU = (column * cellWidth + 0.5f) / texture.getWidth();
        float minV = (row * cellHeight + 0.5f) / texture.getHeight();
        float maxU = ((column + 1) * cellWidth - 0.5f) / texture.getWidth();
        float maxV = ((row + 1) * cellHeight - 0.5f) / texture.getHeight();

        cells[column][row] = texture.getSubTexture(minU, minV, maxU, maxV, cellWidth, cellHeight);
    }

    return cells[column][row];
}

Mathematically, I’m getting the exact same numbers you are for UV coordinates. It goes half a texel in on both sides, rather than right on the edge of both textures.

If I don’t factor in that +/- 0.5f like in your system, I do see lines but that’s not my problem, I got rid of the lines in between textures. My problem is that the texture get’s all pixely, grainy, edgy, bleeding like whenever I move the camera (using gl.translatef() since I’m in 2D space) doesn’t matter which direction, x-axis or y-axis.

Though this problem only happens on one phone of four different kinds. I’m thinking it may have something to do with either my tweening, or the fact that this phone has a really high pixel density.

Would scaling cause something like this?

I changed my renderer class to use Open GL ES 2.X and the problem is still there! It’s on a Samsung Galaxy S4 though I’m not sure if that matters or not. The phone will play other games fine without the bleeding problem so it must be something wrong with my code though I am at a loss for why. :frowning:

I’m going to try a few different things but am really out in the dark at this point. Would appreciate any insights from one of you Open GL ES gurus.

Is using VAO and VBO not permitted in the version you are using? You should handle this via fragment shader, too.

Nothing good comes from GL_BLEND. (That means drop the src_alpha stuff, too).
Although, for what you are doing it may not be a problem, hopefully. I do not have any justification off the top of my head for my bias, sorry. I would if I was at my work station.

I believe that GL_TEXTURE_2D is already enabled, so you don’t have to enable it. But check if it is by default. (Just a pointless suggestion.)

Here is how I calculate my coords…

Lets take an integer that represents a cell. We will call this ‘index’. If we have a 25x25 grid of tiles, then we would have 625 different indices. That means index should: 0 >= index <= 625. Now from right to left you would count from 0-24, 25-49, etc. This format allows us to tell which tile is what. Simple to imagine, but a bit difficult to say without an image. Note: This is not required for doing this because you could use two numbers to determine the X and Y tile in a grid-like fashion, but people like tile IDs…

Now, your image has a width of 25 tile by 25 tile. You need to know the width of each tile in pixels. Let’s say 16x16 pixels per tile. Now, your image has a total length of 2516x2516. You will need the width and height, too.

Once you have that noted, you can start to do some ratios that comply with this system.

float tilex = 25;
float tiley = 25;

float width = 25*16; // 400
float height = 25*16; // 400

// so if your UV coordinates where (0.0625, 0.0625) for the bottom right corner and (0, 0) for the top left
// you would grasp the first tile.
float transx = tilex/width; // on a 0-1 scale, 0.0625 would be per pixel translation in texture coordinates
float transy = tiley/height;

// If you don't have an index, then do this...
float tileUVX = transx * select_tile_x; // where select_tile_x is the number of the tile you want in the X axis
float tileUVY = transy * select_tile_y; // where select_tile_y is the number of the tile you want in the Y axis

// If you went with the index, then do this...
float X = index % tileX; // get the amount X you should translate right
float Y = floor(index/tileY); // May be wrong, doing off top of my head. MIGHT BE index - X.

One important note is to set your texture param to repeat over clamp.

With this, I get NO texture bleeding. I also map my ortho projection matrix to pixel units. So (scale) vec3(1, 1) would yield always 1 pixel by 1 pixel.

You may still get texture bleeding, who knows, but in the case of solutions, I have seen all the solutions that I have.

Yes I’m using one Float Buffer holding vertex data, one Short Buffer holding indices, and then every texture has it’s own Float Buffer for uv coords.

How can I achieve transparency with my drawings without GL_BLEND?

Since switching to Open GL ES 2.X I do not in fact need to enable GL_TEXTURE_2D

My texture coord mapping is correct, it’s got to be something else. At one point I was generating the wrong coordinates and I could see lines on the edge of the texture but when I fixed them they went away.

Like I said the problem is only with one phone. I’ve tested it on 4 others which do not bleed at all.

I’ll try repeat texture parameter and see if it makes a difference.

I recommend an integer buffer for your indices if loading from file. A short is as big as a char, and in the case of maps, etc you can get over 65k indices. (breaking it…) The switch to integer is nothing hard.

To achieve the transparency, which is only an illusion (say mixture of black background and gradient white on top), you can do this in a fragment shader. Very naturally, actually. Just supply the alpha of the pixel and you are all set to go.

Are you sure it is correct? Did you run tests? This is a crucial portion which will lead to this error. Make sure the math lines up. Some GPU are very picky with their pixels and you should use the Half-Pixel trick, too. (For correctness sake…)

See about it here

As the link @ndnwarrior15 gave, there is a picture chart with numbers that are useful.

Lol I’m the same person that submitted that link.

Yes I’ve triple checked the math and the texture coordinates are correct. I had the logcat (android) print out the values it was generating and even did the math on paper. It’s right.

Oh. Post all your files relevant to rendering into the pastebin on here and post the links.

Turns out doing one draw call per tile is bad bad bad. I’ve implemented a batch draw that pumps all the information to the GPU in only one glDrawElements() call.

Aaaaaaand it works! No more bleeding stuff :slight_smile: