[Solved] Spritesheet Bleeding

Started by
2 comments, last by eCustic 11 years, 9 months ago
I have been trying to implement animated sprites using a spritesheet in LWJGL, but I'm having some issues with my sprites bleeding into each other. My sprite sheet is 256 x 512 pixels, with 4 x 4 sprites which are each 64 x 128 pixels, for a walking animation in 4 directions. The problem is that each sprite is positioned so that the pixels of the feet are on the edge of the sprite which causes lines to appear above the head on the sprite below it. However, this doesn't happen consistently, only on certain parts of the screen apparently, and not always the same colour even though it should be the same colour. All of my sprites also seem to blur slightly sometimes.

Here is the code for the draw method of my Sprite class:


public void draw(float x, float y) {
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture.getTextureID());

float currentOffsetX = (float)(offsetX + currentFrame) * spriteTextureWidthRatio;
float currentOffsetY = (float)offsetY * spriteTextureHeightRatio;

GL11.glBegin(GL11.GL_QUADS);

GL11.glTexCoord2f(currentOffsetX, currentOffsetY);
GL11.glVertex2f(x,y);

GL11.glTexCoord2f(currentOffsetX + spriteTextureWidthRatio, currentOffsetY);
GL11.glVertex2f(x + width, y);

GL11.glTexCoord2f(currentOffsetX + spriteTextureWidthRatio, currentOffsetY + spriteTextureHeightRatio);
GL11.glVertex2f(x + width, y + height);

GL11.glTexCoord2f(currentOffsetX, currentOffsetY + spriteTextureHeightRatio);
GL11.glVertex2f(x, y + height);

GL11.glEnd();
}


The spriteTextureWidthRatio and spriteTextureHeightRatio variables are spriteWidth / textureWidth and spriteHeight / textureHeight respectively.

I've read somewhere that the issue might be caused because I'm using floating point values for the texture coordinates. In this case the values for the coordinates will be either 0.0, 0.25, 0.50, 0.75 or 1.0 depending on which part of the sprite sheet is drawn, which would make OpenGL do some weird stuff where it offsets by a half pixel or something, causing the bleeding and the blurriness in some cases. I've heard that I could scale the texture instead using a texture matrix and then access the different parts of the spritesheet with integer values which in this case would be 0 to 4. I don't know how I would go about doing this (I'm fairly new to OpenGL) or if this would solve the problem at all.

I've seen other places where people recommend using a 1 pixel transparent border around every sprite. I think the problem with this solution is that it doesn't work for tilesets where you don't want a border between your tiles.

Either way, I'm hoping someone here can tell me what the right way to do it is. I'm probably only having this problem because I'm such a noob when it comes to OpenGL. smile.png
Advertisement
If your sprites are blurry and you want them pixelated, the thing to try would be


GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER,GL11.GL_NEAREST);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER,GL11.GL_NEAREST);

When you create your textures, which will use nearest-neighbor sampling instead of mipmapping or linear interpolation for sampling texels that don't line up perfectly with the screen. (so a pixel that's halfway between two texels will be the color of the one it is closest to)

If that doesn't clear up the lines, another option to try (possibly along with the previous one) would be to add 0.5/spriteHeight to your texture coordinates' Y value, and see if that doesn't help.

Failing that, the other solutions I know of involve using shaders, which it doesn't look like you're doing here. LWJGL has some documentation on using them (and VBO's, which are unrelated here but quite useful) on its wiki, which could help you get started.

I've seen other places where people recommend using a 1 pixel transparent border around every sprite. I think the problem with this solution is that it doesn't work for tilesets where you don't want a border between your tiles.


yes, you need a 1 pixel border, however, with tile sheets, instead of making it transparent, you need to make your border be an extension of the last pixel, for example:

27zlt1i.png

^^this is a tile sheet i use, each tile is 64x64. but the border makes them 66x66, however, if you look at the border, each pixel is == to the pixel directly left/right/below/above it.

i made this example to see a bit easier of what's being done:

2njg6xl.png
Check out https://www.facebook.com/LiquidGames for some great games made by me on the Playstation Mobile market.
Thanks for the help guys. I've solved the problem. Before posting the OP I tried doing as Koehler mentioned:


GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER,GL11.GL_NEAREST);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER,GL11.GL_NEAREST);


This didn't work and I couldn't understand why. After reading Koehler's post I realized that it might be because I'm using the TextureLoader from the Slick2D library (I didn't want to write my own texture loader).
I found the API again and saw that one of the overloads of the getTexture method had a filter input, so the solution to the problem was changing the code in my TextureStore class from:


texture = TextureLoader.getTexture("PNG", ResourceLoader.getResourceAsStream(texturesPath + textureRef));


to


texture = TextureLoader.getTexture("PNG", ResourceLoader.getResourceAsStream(texturesPath + textureRef), GL11.GL_NEAREST);


Hope this helps anyone who is having similar issues. Also I feel this is a cleaner solution than having to modify all your texture files to have a 1 pixel border.

Thanks again! happy.png

This topic is closed to new replies.

Advertisement