67
\$\begingroup\$

I have seen many examples of how to render sprites from a spritesheet but I havent grasped why it is the most common way of dealing with sprites in 2d games.

I have started out with 2d sprite rendering in the few demo applications I've made by dealing with each animation frame for any given sprite type as its own texture - and this collection of textures is stored in a dictionary. This seems to work for me, and suits my workflow pretty well, as I tend to make my animations as gif/mng files and then extract the frames to individual pngs.

Is there a noticeable performance advantage to rendering from a single sheet rather than from individual textures? With modern hardware that is capable of drawing millions of polygons to the screen a hundred times a second, does it even matter for my 2d games which just deal with a few dozen 50x100px rectangles?

The implementation details of loading a texture into graphics memory and displaying it in XNA seems pretty abstracted. All I know is that textures are bound to the graphics device when they are loaded, then during the game loop, the textures get rendered in batches. So it's not clear to me whether my choice affects performance.

I suspect that there are some very good reasons most 2d game developers seem to be using them, I just don't understand why.

\$\endgroup\$
1
  • \$\begingroup\$ No it doesn't really matter too much for your 50 odd sprites. But what's to lose? \$\endgroup\$ Jan 4, 2011 at 16:43

9 Answers 9

73
\$\begingroup\$

A strong argument for using spritesheets is that the number of available textures on a graphic card can be limited. Therefore your graphics library would constantly have to remove texture and re-allocate textures on the GPU. It's much more efficient to just allocate a large texture once.

Also consider that texture sizes are usually power of 2. So if you have a 50x100px Sprite, you'll allocate textures with the size 64x128px or in the worse case 128x128px. That's just wasting graphics memory. Better pack all the sprites into a 1024x1024px texture, which would allow 20x10 sprites and you'll only lose 24 pixels horizontally and vertically. Sometimes even sprites of different sizes are combined into one huge sprite-sheet to use the texture as efficient as possible.

Addendum: A very important reason to use sprite-sheets is to reduce the amount of draw-calls on your GPU, which can have a notable impact on performance. This has been stated in other answers and I'm adding this for the sake of completeness so that this gets some more visibility.

\$\endgroup\$
6
  • 1
    \$\begingroup\$ Thanks, I hadn't considered either of those points - Do you know roughly what the limit is on the number of available textures? I've never seen this stat mentioned on graphics specifications - is the limit basically equal to the amount of graphics RAM? \$\endgroup\$
    – Columbo
    Jan 4, 2011 at 17:16
  • \$\begingroup\$ Usually the limit would be the GPU memory, yes. I thought there were some restrictions on the number of textures on older cards but I can't seem to find a reference that proves that point. \$\endgroup\$
    – bummzack
    Jan 4, 2011 at 17:51
  • 12
    \$\begingroup\$ Even if there isn't a limit on quantity, the bus-traffic for moving lots of little images is not as efficient as one (or a few) large transfer(s). \$\endgroup\$
    – Mordachai
    Jan 4, 2011 at 21:24
  • 5
    \$\begingroup\$ Good points, but the most important aspect s to minimise pipeline stalls by keeping the draw call count down. GPUs prefer a small amount of large jobs, rather than a large ammont of small jobs. Putting all your sprites in to a small ammount of large sheets means you can set the textue stage up once and draw lots of spites at once in a batch. Spritebatch does this for you. If you have more than one spritesheet, make sure to tell spritebatch to sort by texture \$\endgroup\$
    – Cubed2D
    Jan 11, 2011 at 14:33
  • 1
    \$\begingroup\$ Hello from the future! Nearly all graphics cards now-a-days support non-power-of-two texture sizes! \$\endgroup\$
    – Casey
    Mar 11, 2021 at 22:21
37
\$\begingroup\$

I'd say the arguement to use would be the ability to render multiple things in a single draw call. Take for example font rendering, without a spritesheet you'd need to render each character with a separate texture swap followed by a draw call. Throw them into a spritesheet and you can render entire sentences with a single draw call (the difference characters in the font being picked out by just specifying the different UV's for the corners). This is a much more efficient way of rendering when a very real overhead of rendering stuff on a lot of platforms is in making too many API calls.

It can also help save space, but it depends on what your packing into the spritesheet in the first place.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ +1 Touches upon draw calls. (something I didn't see in the accepted answer) \$\endgroup\$ Jan 10, 2011 at 19:03
12
\$\begingroup\$

Each draw call has a certain amount of overhead. By using sprite sheets you can batch the drawing of things that aren't using the same frame of an animation (or more generally, everything that's on the same material) greatly enhancing performance. This may not matter too much for modern PCs depending on your game, but it definitely matters on, say, the iPhone.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ It definitely still matters. Graphics hardware has been optimized toward pushing tons of polygons for a small number of detailed models (eg. characters) because most games tend in that direction. The result is that you need to push as many polygons as possible in each of just a couple dozen draw calls. Game engines that render large scenes like cities often combine multiple textures into one on the fly in order to reduce draw calls. \$\endgroup\$
    – jhocking
    Apr 9, 2011 at 15:00
  • \$\begingroup\$ I'm definitely wondering if the texture u,v mapping in a lot of 3D hardware, plus bit blitting operations benefit from the sprite sheet. \$\endgroup\$
    – Joe Plante
    May 2, 2013 at 18:41
7
\$\begingroup\$

In addition to performance considerations, sprite sheets can be handy when creating the art; each character can be in its own sheet, and you can see all the frames just by scrolling around. It helps me keep a consistent look across all the frames.

Additionally, I code in AS3, and each image file requires a separate embed instruction. I'd rather have a single embed of an entire spritesheet than 24 embeds for all the frames, even if I'm using a separate resource class.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ +1. Although the OP isn't using Flash, the embedding or loading is also a point in favor of spritesheets. It's also relevant when assets are loaded from a Webserver where 1 request is preferred over several hundred requests (for each "frame"). \$\endgroup\$
    – bummzack
    Jan 4, 2011 at 17:55
  • \$\begingroup\$ Definitely you want to reduce server requests for an online game. We considered whether it is better to put the images into a .swf or a spritesheet because both accomplish this main goal (we eventually decided spritesheets are less labor intensive for our artists). \$\endgroup\$
    – jhocking
    Apr 12, 2012 at 0:11
7
\$\begingroup\$

Another reason so use spritesheets with XNA is that with Xbox360 development there's a known issue with slow deploy/load times in relation to the number of files you have in your project. So combining lots of small image files into a single image file will help combat that issue.

\$\endgroup\$
5
\$\begingroup\$

I'm not going to mention memory/GPU here, since there's enough answers like that.

Instead, it can clear up your art as you work on it - and after. Instead of having to flick through 10 images to see the walk cycle, you can see all the frames in one go. If you wanted to distribute this, you've only got 1 file to deal with instead of 10.

And then it's also cleaner (from a organizing point of view) to have character.png and enemy.png over characterwalk01 through to characterwalk10, then characterattack01 to characterattack05, and it goes on.

\$\endgroup\$
4
\$\begingroup\$

The graphics memory does not have a bloat up memory management like file systems on disks; the oposite is the case: it is kept simple and fast.

One such simple and fast memory mangement might be like having only one single giant 4096x4096 sprite that is cut in multiple smaller sprites by halfing its width and/or height. (There exists a similar 1-dimensional memory-managing technique, but I forgot the name.) Eventually, Defragmentation has to be performed.

To skip such memory management at run-time, developers fill single large sprites with multiple smaller sprites automatically at compile-time or even while in the desing-process of the graphics.

\$\endgroup\$
3
\$\begingroup\$

Also don't forget the I/O operations it might save you during initialization. If you are loading from a CD drive, each file is an extra I/O call, and might take some time to seek (modern HDD's are about 15 ms per file, CD's maybe 50-100ms?). This can save you a lot of initialization time as only one file has to be fetched. It also allows your OS to cache these I/O operations, in case your application is doing something else (like waiting for GPU).

\$\endgroup\$
1
  • 1
    \$\begingroup\$ In the other end if you want to solve file seek problem, you could have all your sprites packed in a single file, using a custom format. Most games do that. \$\endgroup\$
    – tigrou
    May 12, 2012 at 18:16
0
\$\begingroup\$

Other than being more performance efficient, I find it simply easier. It requires a little extra work to make sure your images are always within their bounds when creating the art, but it's a lot easier being able to see all the images you're dealing with at the moment.

It's also easier to code, in my opinion. I simply have an array of objects like:

sheet = {
    img: (the actual image),
    rects: [
        {x:0, y:0, w:32, h:32},
        {x:32, y:0, w:32, h:32},
        {x:64, y:0, w:32, h:32}
    ]
};

sheets.push(sheet);

Then for each item I give it two values, sheet and rect. The sheet would be the index in the array of objects, and the rect would be the index in that sheet's rects array.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .