Texture filtering: sprite sheets

Texture filtering: sprite sheets

  • Comments 12

You can control what happens when texture filtering reads from past the edge of a texture using the SamplerState.AddressU and AddressV properties. But what if you are using a sprite sheet? The sampler address modes know nothing about how your sprites have been packed together, so when you filter a sprite from a sheet, the GPU will happily sample from outside the area you told it to draw. This causes colors from one sprite to show up along the edges of whatever happens to be packed next to it, which is unlikely to be what you wanted!

Possible solutions:

  • Don't use sprite sheets. This is especially a good idea if you want mipmaps, as it is near impossible to make sprite sheets and mipmaps play nice together.

  • Don't use filtering. Point sampling will never read past the edge of the region you specify, so it has no problem with sprite sheets. But then, point sampling tends to look rather ugly, and who wants that?

  • Roll your own filtering in the pixel shader. If you set the GPU to point sampling mode, you could write a shader that implements bilinear filtering by averaging several point samples, and this shader could know about your sprite sheet and thus avoid reading from outside the current sprite. This is likely to be slower than not using sprite sheets at all, though, so not usually a good idea.

  • Add a gutter region around each sprite. Given this 3x3 source image:
A B C
D E F
G H I

Expand it to 5x5:

a a b c c
a A B C c
d D E F f
g G H I i
g g h i i

Pack the 5x5 version into your sprite sheet, but just draw the inner 3x3 (shown in bold). Now the filtering hardware can happily read past the edge of the specified region, and will pick up sensible color values from the gutter pixels (shown in italic).

Adding gutters by hand soon gets boring, but this is easy to automate. Our Sprite Sheet sample provides a content processor that will pack any number of textures into a sprite sheet, automatically adding the necessary gutters to make filtering work correctly.

  • What would you use instead of sprite sheets?

  • > What would you use instead of sprite sheets?

    Individual textures, one per sprite.

  • Thanks again for your blog, it rocks! Regarding the gutter regions, that would still not work for mip mapping, would it?

  • I suppose it's largely irrelevant when dealing with regular view-aligned sprites, but wouldn't the 1tx gutter approach be inadequate if viewing the sprite at a shallow angle with anisotropic filtering?

  • I remember seeing in the Sprite Sheet sample that mipsmaps are generated for the resulting spritesheet it creates.

    Why dont spritesheets (with an edge around each sprite) and mipmaps go well together and are there any workarounds other than not using spritesheets or not using mipmaps?

  • Lars: quite right, a single pixel gutter may not be enough when using anisotropic filtering. In that case you could increase the gutter size to match your max anisotropy setting. I've never actually come across this problem in practice, though, since sprite sheets are most often used with 2D graphics, and anisotropic filtering is only relevant in 3D.

    Beringela: our Sprite Sheet sample does not create any mipmaps.

    Beringela and Roel: actually I think I'll do another post about the problems of mipmapped sprite sheets.

  • Great, I look forward to you writing about mipmapped spritesheet issues, I am a huge fan of your blog.

    The reason I thought the sprite sheet sample used mipmaps is that in SpriteSheetProcessor.cs there is a line at the end of the .Process method that says this:

    spriteSheet.Texture.Mipmaps.Add(packedSprites);

    Does this not add mipmaps?

  • This line:

       spriteSheet.Texture.Mipmaps.Add(packedSprites);

    just adds a single image to the mipchain collection. That's not a series of mipmaps, it's the main texture itself! (if you didn't have a single image in there, there would be no data in the texture at all).

    To have a mip chain, you need more than one image, each one half the size of the previous.

  • Can you explain why there's no gutter between the middle sprites -- E, for example? Why won't textures from D get sampled in to E's left edge?

    Great series, by the way.

  • > Can you explain why there's no gutter between the middle sprites -- E, for example? Why won't textures from D get sampled in to E's left edge?

    D, E, etc, refer to pixels, not sprites!

    This example was showing how to add a gutter around just a single 3x3 sprite.

  • What would you do about using a sprite sheet that contains an animation seq of a single sprite?  How would you do mipmaping there?  Use a separate texture for each texture in the animation?  

    ShawnHargreaves " actually I think I'll do another post about the problems of mipmapped sprite sheets"

    Did you ever do that post? I would love to see it!!

    Thanks

  • > What would you do about using a sprite sheet that contains an animation seq of a single sprite?

    If am I drawing the sprites in 2D, and never scaling them down more than 2x, I would not use mipmaps.

    If am I drawing the sprites in 3D, or in 2D and scaling them down more than 2x, I would not use a sprite sheet, and just store each frame as a separate texture.

    > Did you ever do that post? I would love to see it!!

    blogs.msdn.com/.../texture-filtering-mipmapped-sprite-sheets.aspx

Page 1 of 1 (12 items)
Leave a Comment
  • Please add 5 and 2 and type the answer here:
  • Post