Jump to content

  • Log In with Google      Sign In   
  • Create Account

FREE SOFTWARE GIVEAWAY

We have 4 x Pro Licences (valued at $59 each) for 2d modular animation software Spriter to give away in this Thursday's GDNet Direct email newsletter.


Read more in this forum topic or make sure you're signed up (from the right-hand sidebar on the homepage) and read Thursday's newsletter to get in the running!


[Solved] Spritesheet Bleeding


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
3 replies to this topic

#1 eCustic   Members   -  Reputation: 112

Like
0Likes
Like

Posted 06 July 2012 - 07:43 AM

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. Posted Image

Edited by eCustic, 11 July 2012 - 04:49 AM.


Sponsor:

#2 Koehler   Members   -  Reputation: 228

Like
1Likes
Like

Posted 06 July 2012 - 09:38 AM

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.

Edited by Koehler, 06 July 2012 - 09:38 AM.


#3 slicer4ever   Crossbones+   -  Reputation: 3987

Like
0Likes
Like

Posted 06 July 2012 - 11:37 AM

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:

Posted Image

^^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:

Posted Image

Edited by slicer4ever, 06 July 2012 - 11:44 AM.

Check out https://www.facebook.com/LiquidGames for some great games made by me on the Playstation Mobile market.

#4 eCustic   Members   -  Reputation: 112

Like
0Likes
Like

Posted 06 July 2012 - 01:26 PM

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! Posted Image




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS