SpriteBatch and custom renderstates in XNA Game Studio 4.0

Originally posted to Shawn Hargreaves Blog on MSDN, Monday, April 5, 2010

The theory:

SpriteBatch was designed to provide an easy and efficient way to draw 2D sprites. Everything it can do, you can also do yourself by creating vertices and calling the lower level Draw* APIs, so our goal with SpriteBatch was to make the most common operations easier, not to support every obscure corner case.

In practice:

While testing Game Studio 1.0, we learned that corner cases are common even in simple 2D games! And the SpriteBatch API turned out to be so convenient, it was considerably irritating every time we wanted to do something outside the limited options provided by the SpriteBlendMode enum. We considered adding more state parameters to SpriteBatch.Begin, but our API exposed too many renderstates for that to be practical.

Instead, we added SpriteSortMode.Immediate, which lets you set whatever state you want directly onto the GraphicsDevice. This made many things possible, although not exactly elegant:

But hey. This was late in the 1.0 development cycle, so we had to do something simple and low risk.

We can do better:

Game Studio 4.0 makes it possible to specify the entire device state with just four state objects. We changed SpriteBatch.Begin to take advantage of this, removing the SpriteBlendMode enum, and instead directly specifying one or more state objects.

XNA Framework 3.1 XNA Framework 4.0
spriteBatch.Begin(); spriteBatch.Begin();
spriteBatch.Begin(SpriteBlendMode.None); spriteBatch.Begin(SpriteSortMode.Deferred,
                  BlendState.Opaque);
spriteBatch.Begin(SpriteBlendMode.Additive,
                  SpriteSortMode.FrontToBack,
                  SaveStateMode.None);
spriteBatch.Begin(SpriteSortMode.FrontToBack,
                  BlendState.Additive);
spriteBatch.Begin(SpriteBlendMode.AlphaBlend,
                  SpriteSortMode.Deferred,
                  SaveStateMode.None,
                  transformMatrix);
spriteBatch.Begin(SpriteSortMode.Deferred,
                  BlendState.AlphaBlend,
                  null, null, null, null,
                  transformMatrix);

Notes:

        spriteBatch.Begin(SpriteSortMode.Texture,
                          BlendState.Additive,
                          SamplerState.PointWrap,
                          DepthStencilState.DepthRead,
                          RasterizerState.CullNone);

This is not limited to the built-in state objects, so SpriteBatch can now use any custom blend state, sampler state, etc, with any sort mode.

Blog index   -   Back to my homepage