The cost of SpriteBlendMode.AlphaBlend and the SpriteSortOptions

The SpriteBatch.Begin method has a couple of parameters that control how the sprites are rendered on the screen. Most people are aware of SpriteBlendMode.AlphaBlend, but for transparency to work correctly, you need to ensure that your sprites are being drawn back to front.

Now, if you're just using transparency to knock the background out of an image, then you might not notice any problems - even if you draw your sprites in the wrong order. In this case the effect is localized to the edges of your objects where they're less likely to draw attention.

But if you have large regions of transparency, the impact of not drawing back to front can be quite noticeable.

The above image shows what happens when 5 circles (white with alpha=68%) are drawn in the wrong order and the correct order. On the left side, the front circle is drawn first so it is blended with the background image (resulting in the blue outline) and the depth buffer prevents the back circles from being drawn behind the front circle. The right side shows the desired effect, where the front circle is drawn last and is blended correctly with the back circles.

This is where SpriteSortOptions comes into the picture (so to speak). With this option, you draw your sprites in any order (but at the correct depth) and the right thing will happen.

So the next questions are : How expensive is it to have the SpriteBatch class manage our sprite sort order? Is it better to sort the sprites once (in your app) and then draw them in the correct order?

To test this, I wrote a simple app that creates a bunch of 64x64 sprites and places them at random depths and locations. I then plotted the FPS as I increased the number of sprites:

The lines in this graph are for SpriteBlendMode.None (in red), SpriteBlendMode.AlphaBlend (in green), and AlphaBlend with SpriteSortOptions.BackToFront (in blue). The gray line at the top is for SpriteSortOptions.FrontToBack, which is (surprisingly) faster than SpriteBlendMode.None but blends the sprites incorrectly. [Reminder: these data points are from the beta XNA release]

If you sort your own sprites and draw them in the correct order, then you get to use the green line. For large numbers (> 500) of sprites, this can be a big win.

Having SpriteBatch sort your sprites for you limits you to around 400 sprites (64x64) before it starts to impact the framerate. If you're content with 30 fps, then you're good up to 1000 sprites.

Of course, if you don't mind having your sprites blended incorrectly, you can have even more.

[Note that the beta XNA release sorts the sprites front to back when you specify SpriteSortOptions.BackToFront. You need to get the bizarro-world version of XNA to have BackToFront actually mean back to front. Or wait for the release version, I imagine. ^_^

Fortunately, FrontToBack in the beta means back to front, so you can use that as a workaround. In this post, I've applied the workaround so when I say "BackToFront" I'm really using SpriteSortOptions.FrontToBack (and vice versa).]

Comments

  • Anonymous
    September 10, 2006
    How does this compare to using the “layer depth” parameter in the SpriteBatch.Draw() method? Does that “layer depth” parameter really do anything? [The layerDepth parameter to SpriteBatch.Draw is how you set the depth of the sprite. Without this, the depth sorting options won't do anything useful (since everything will be at the same default depth). So the above discussion is assuming that you're setting the depth via this parameter. -GaryKac]

  • Anonymous
    September 10, 2006
    One important test parameter I forgot to mention was the machine that I ran my test on:

    HP Pavilion dv5000 laptop with Centrino Duo T2300 1.66GHz, 1Gb RAM, nVidia GeForce Go 7400 and two Xbox 360 controllers.

    Your mileage (or kilometerage) may vary.